Merge "Import translations. DO NOT MERGE"
diff --git a/api/removed.txt b/api/removed.txt
index e7b573b..f52b39a 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -73,7 +73,6 @@
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
- field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 15de5c4..9f3970d 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -71,7 +71,6 @@
method public deprecated android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public deprecated android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
- field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e7b573b..f52b39a 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -73,7 +73,6 @@
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
- field public static final deprecated int FLAG_EVICT_CE_KEY = 1; // 0x1
}
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 588a1bf..b60aed6 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -51,6 +51,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.IUserManager;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -347,7 +348,7 @@
private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
- public void send(int code, Intent intent, String resolvedType,
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
try {
mResult.offer(intent, 5, TimeUnit.SECONDS);
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 000420f..5fedc9e 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -84,6 +84,11 @@
int main(int argc, char** argv)
{
+ // setThreadPoolMaxThreadCount(0) actually tells the kernel it's
+ // not allowed to spawn any additional threads, but we still spawn
+ // a binder thread from userspace when we call startThreadPool().
+ // See b/36066697 for rationale
+ ProcessState::self()->setThreadPoolMaxThreadCount(0);
ProcessState::self()->startThreadPool();
const char* pname = argv[0];
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6fa0a6d..a8183f2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -976,7 +976,7 @@
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
- if (getApplicationInfo().targetSdkVersion >= O && mActivityInfo.isFixedOrientation()) {
+ if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
ta.recycle();
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 0dfaf6a..e9ee1386 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -169,7 +169,8 @@
* Sets how long a {@link PendingIntent} can be temporarily whitelist to by bypass restrictions
* such as Power Save mode.
*/
- public abstract void setPendingIntentWhitelistDuration(IIntentSender target, long duration);
+ public abstract void setPendingIntentWhitelistDuration(IIntentSender target,
+ IBinder whitelistToken, long duration);
/**
* Allow DeviceIdleController to tell us about what apps are whitelisted.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 68021d9..1dcc3e2 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -65,6 +65,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IStorageManager;
+import android.os.storage.StorageManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -375,7 +376,9 @@
checkMode(mode);
if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
if (isCredentialProtectedStorage()
- && !getSystemService(UserManager.class).isUserUnlocked() && !isBuggy()) {
+ && !getSystemService(StorageManager.class).isUserKeyUnlocked(
+ UserHandle.myUserId())
+ && !isBuggy()) {
throw new IllegalStateException("SharedPreferences in credential encrypted "
+ "storage are not available until after user is unlocked");
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 68fce75..9552d17 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -562,8 +562,8 @@
void notifyLockedProfile(int userId);
void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
void sendIdleJobTrigger();
- int sendIntentSender(in IIntentSender target, int code, in Intent intent,
- in String resolvedType, in IIntentReceiver finishedReceiver,
+ int sendIntentSender(in IIntentSender target, in IBinder whitelistToken, int code,
+ in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver,
in String requiredPermission, in Bundle options);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index cc7e0fd..1c1883b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -71,6 +71,7 @@
int getDeletedChannelCount(String pkg, int uid);
void deleteNotificationChannelGroup(String pkg, String channelGroupId);
ParceledListSlice getNotificationChannelGroups(String pkg);
+ boolean onlyHasDefaultChannel(String pkg, int uid);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 06509ae..4294eab 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -42,8 +42,10 @@
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -835,6 +837,22 @@
public ArraySet<PendingIntent> allPendingIntents;
/**
+ * Token identifying the notification that is applying doze/bgcheck whitelisting to the
+ * pending intents inside of it, so only those will get the behavior.
+ *
+ * @hide
+ */
+ static public IBinder whitelistToken;
+
+ /**
+ * Must be set by a process to start associating tokens with Notification objects
+ * coming in to it. This is set by NotificationManagerService.
+ *
+ * @hide
+ */
+ static public IBinder processWhitelistToken;
+
+ /**
* {@link #extras} key: this is the title of the notification,
* as supplied to {@link Builder#setContentTitle(CharSequence)}.
*/
@@ -1823,6 +1841,13 @@
{
int version = parcel.readInt();
+ whitelistToken = parcel.readStrongBinder();
+ if (whitelistToken == null) {
+ whitelistToken = processWhitelistToken;
+ }
+ // Propagate this token to all pending intents that are unmarshalled from the parcel.
+ parcel.setClassCookie(PendingIntent.class, whitelistToken);
+
when = parcel.readLong();
creationTime = parcel.readLong();
if (parcel.readInt() != 0) {
@@ -1929,6 +1954,7 @@
* @hide
*/
public void cloneInto(Notification that, boolean heavy) {
+ that.whitelistToken = this.whitelistToken;
that.when = this.when;
that.creationTime = this.creationTime;
that.mSmallIcon = this.mSmallIcon;
@@ -2158,6 +2184,7 @@
private void writeToParcelImpl(Parcel parcel, int flags) {
parcel.writeInt(1);
+ parcel.writeStrongBinder(whitelistToken);
parcel.writeLong(when);
parcel.writeLong(creationTime);
if (mSmallIcon == null && icon != 0) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 704e912..bc7fcf5 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -101,21 +101,11 @@
/**
* @hide
*/
- public static final int USER_LOCKED_ALLOWED = 0x00000040;
-
- /**
- * @hide
- */
public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
/**
* @hide
*/
- public static final int USER_LOCKED_AUDIO_ATTRIBUTES = 0x00000100;
-
- /**
- * @hide
- */
public static final int[] LOCKABLE_FIELDS = new int[] {
USER_LOCKED_PRIORITY,
USER_LOCKED_VISIBILITY,
@@ -123,9 +113,7 @@
USER_LOCKED_LIGHTS,
USER_LOCKED_VIBRATION,
USER_LOCKED_SOUND,
- USER_LOCKED_ALLOWED,
USER_LOCKED_SHOW_BADGE,
- USER_LOCKED_AUDIO_ATTRIBUTES
};
private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -273,6 +261,13 @@
/**
* @hide
*/
+ public void unlockFields(int field) {
+ mUserLockedFields &= ~field;
+ }
+
+ /**
+ * @hide
+ */
public void setDeleted(boolean deleted) {
mDeleted = deleted;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index dc432af..11d9b5e 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -93,6 +93,7 @@
*/
public final class PendingIntent implements Parcelable {
private final IIntentSender mTarget;
+ private IBinder mWhitelistToken;
/** @hide */
@IntDef(flag = true,
@@ -656,7 +657,7 @@
*
*/
public IntentSender getIntentSender() {
- return new IntentSender(mTarget);
+ return new IntentSender(mTarget, mWhitelistToken);
}
/**
@@ -870,7 +871,7 @@
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
int res = ActivityManager.getService().sendIntentSender(
- mTarget, code, intent, resolvedType,
+ mTarget, mWhitelistToken, code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
: null,
@@ -1085,7 +1086,9 @@
= new Parcelable.Creator<PendingIntent>() {
public PendingIntent createFromParcel(Parcel in) {
IBinder target = in.readStrongBinder();
- return target != null ? new PendingIntent(target) : null;
+ return target != null
+ ? new PendingIntent(target, in.getClassCookie(PendingIntent.class))
+ : null;
}
public PendingIntent[] newArray(int size) {
@@ -1108,31 +1111,39 @@
}
/**
- * Convenience function for reading either a Messenger or null pointer from
- * a Parcel. You must have previously written the Messenger with
+ * Convenience function for reading either a PendingIntent or null pointer from
+ * a Parcel. You must have previously written the PendingIntent with
* {@link #writePendingIntentOrNullToParcel}.
*
- * @param in The Parcel containing the written Messenger.
+ * @param in The Parcel containing the written PendingIntent.
*
- * @return Returns the Messenger read from the Parcel, or null if null had
+ * @return Returns the PendingIntent read from the Parcel, or null if null had
* been written.
*/
@Nullable
public static PendingIntent readPendingIntentOrNullFromParcel(@NonNull Parcel in) {
IBinder b = in.readStrongBinder();
- return b != null ? new PendingIntent(b) : null;
+ return b != null ? new PendingIntent(b, in.getClassCookie(PendingIntent.class)) : null;
}
/*package*/ PendingIntent(IIntentSender target) {
mTarget = target;
}
- /*package*/ PendingIntent(IBinder target) {
+ /*package*/ PendingIntent(IBinder target, Object cookie) {
mTarget = IIntentSender.Stub.asInterface(target);
+ if (cookie != null) {
+ mWhitelistToken = (IBinder)cookie;
+ }
}
/** @hide */
public IIntentSender getTarget() {
return mTarget;
}
+
+ /** @hide */
+ public IBinder getWhitelistToken() {
+ return mWhitelistToken;
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d26d7e5..c09b688 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3058,13 +3058,6 @@
*/
public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1;
- /**
- * Instead use {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}.
- * @removed
- */
- @Deprecated
- public static final int FLAG_EVICT_CE_KEY = 1;
-
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY})
diff --git a/core/java/android/content/IIntentSender.aidl b/core/java/android/content/IIntentSender.aidl
index 45c62d4..21ea2fe 100644
--- a/core/java/android/content/IIntentSender.aidl
+++ b/core/java/android/content/IIntentSender.aidl
@@ -22,6 +22,6 @@
/** @hide */
oneway interface IIntentSender {
- void send(int code, in Intent intent, String resolvedType,
+ void send(int code, in Intent intent, String resolvedType, in IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, in Bundle options);
}
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 4adb5b7..0a456b5 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -56,6 +56,7 @@
*/
public class IntentSender implements Parcelable {
private final IIntentSender mTarget;
+ IBinder mWhitelistToken;
/**
* Exception thrown when trying to send through a PendingIntent that
@@ -187,7 +188,7 @@
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
- int res = ActivityManager.getService().sendIntentSender(mTarget,
+ int res = ActivityManager.getService().sendIntentSender(mTarget, mWhitelistToken,
code, intent, resolvedType,
onFinished != null
? new FinishedDispatcher(this, onFinished, handler)
@@ -365,6 +366,12 @@
}
/** @hide */
+ public IntentSender(IIntentSender target, IBinder whitelistToken) {
+ mTarget = target;
+ mWhitelistToken = whitelistToken;
+ }
+
+ /** @hide */
public IntentSender(IBinder target) {
mTarget = IIntentSender.Stub.asInterface(target);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9a5482a..ca15275 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -157,6 +157,7 @@
MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
MATCH_INSTANT,
+ MATCH_STATIC_SHARED_LIBRARIES,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
})
@@ -177,6 +178,7 @@
MATCH_SYSTEM_ONLY,
MATCH_UNINSTALLED_PACKAGES,
MATCH_INSTANT,
+ MATCH_STATIC_SHARED_LIBRARIES,
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
@@ -475,6 +477,16 @@
public static final int MATCH_EXPLICITLY_VISIBLE_ONLY = 0x02000000;
/**
+ * Internal {@link PackageInfo} flag: include static shared libraries.
+ * Apps that depend on static shared libs can always access the version
+ * of the lib they depend on. System/shell/root can access all shared
+ * libs regardless of dependency but need to explicitly ask for them
+ * via this flag.
+ * @hide
+ */
+ public static final int MATCH_STATIC_SHARED_LIBRARIES = 0x04000000;
+
+ /**
* Internal flag used to indicate that a system component has done their
* homework and verified that they correctly handle packages and components
* that come and go over time. In particular:
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 0b0f048..f33c751 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -103,7 +103,8 @@
}
/**
- * Return the number of indices in the array that actually have data.
+ * Returns the number of indices in the array that actually have data. Attributes with a value
+ * of @empty are included, as this is an explicit indicator.
*
* @throws RuntimeException if the TypedArray has already been recycled.
*/
@@ -116,7 +117,8 @@
}
/**
- * Returns an index in the array that has data.
+ * Returns an index in the array that has data. Attributes with a value of @empty are included,
+ * as this is an explicit indicator.
*
* @param at The index you would like to returned, ranging from 0 to
* {@link #getIndexCount()}.
@@ -1017,7 +1019,7 @@
* @param outValue TypedValue object in which to place the attribute's
* data.
*
- * @return {@code true} if the value was retrieved, false otherwise.
+ * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
public boolean getValue(@StyleableRes int index, TypedValue outValue) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5edefb5..dadc5f5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -40,6 +40,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
@@ -2695,6 +2696,28 @@
}
}
+ /**
+ * Constant error codes used by ConnectivityService to communicate about failures and errors
+ * across a Binder boundary.
+ * @hide
+ */
+ public interface Errors {
+ static int TOO_MANY_REQUESTS = 1;
+ }
+
+ /** @hide */
+ public static class TooManyRequestsException extends RuntimeException {}
+
+ private static RuntimeException convertServiceException(ServiceSpecificException e) {
+ switch (e.errorCode) {
+ case Errors.TOO_MANY_REQUESTS:
+ return new TooManyRequestsException();
+ default:
+ Log.w(TAG, "Unknown service error code " + e.errorCode);
+ return new RuntimeException(e);
+ }
+ }
+
private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
/** @hide */
public static final int CALLBACK_PRECHECK = BASE + 1;
@@ -2886,6 +2909,8 @@
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ throw convertServiceException(e);
}
return request;
}
@@ -3127,6 +3152,8 @@
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ throw convertServiceException(e);
}
}
@@ -3226,6 +3253,8 @@
mService.pendingListenForNetwork(request.networkCapabilities, operation);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ throw convertServiceException(e);
}
}
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 65025fb..8d85880 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -1548,6 +1548,7 @@
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
+ p.adoptClassCookies(parcel);
if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
+ ": " + length + " bundle bytes starting at " + offset);
p.setDataPosition(0);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c5c743b..f4a9ef6 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -204,6 +204,8 @@
private boolean mOwnsNativeParcelObject;
private long mNativeSize;
+ private ArrayMap<Class, Object> mClassCookies;
+
private RuntimeException mStack;
private static final int POOL_SIZE = 6;
@@ -293,6 +295,7 @@
private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
+ private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
private static native byte[] nativeReadBlob(long nativePtr);
@FastNative
private static native int nativeReadInt(long nativePtr);
@@ -497,6 +500,24 @@
return nativeCompareData(mNativePtr, other.mNativePtr);
}
+ /** @hide */
+ public final void setClassCookie(Class clz, Object cookie) {
+ if (mClassCookies == null) {
+ mClassCookies = new ArrayMap<>();
+ }
+ mClassCookies.put(clz, cookie);
+ }
+
+ /** @hide */
+ public final Object getClassCookie(Class clz) {
+ return mClassCookies != null ? mClassCookies.get(clz) : null;
+ }
+
+ /** @hide */
+ public final void adoptClassCookies(Parcel from) {
+ mClassCookies = from.mClassCookies;
+ }
+
/**
* Report whether the parcel contains any marshalled file descriptors.
*/
@@ -2197,11 +2218,8 @@
* given byte array.
*/
public final void readByteArray(byte[] val) {
- // TODO: make this a native method to avoid the extra copy.
- byte[] ba = createByteArray();
- if (ba.length == val.length) {
- System.arraycopy(ba, 0, val, 0, ba.length);
- } else {
+ boolean valid = nativeReadByteArray(mNativePtr, val, (val != null) ? val.length : 0);
+ if (!valid) {
throw new RuntimeException("bad array lengths");
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7374586..39f48df 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6968,6 +6968,13 @@
public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
/**
+ * Whether the launcher should show any notification badges.
+ * The value is boolean (1 or 0).
+ * @hide
+ */
+ public static final String NOTIFICATION_BADGING = "notification_badging";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -7062,7 +7069,8 @@
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
ASSIST_GESTURE_ENABLED,
ASSIST_GESTURE_SENSITIVITY,
- VR_DISPLAY_MODE
+ VR_DISPLAY_MODE,
+ NOTIFICATION_BADGING
};
/**
diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java
index b3fe8a8..bf33519 100644
--- a/core/java/android/util/MemoryIntArray.java
+++ b/core/java/android/util/MemoryIntArray.java
@@ -56,7 +56,7 @@
private final boolean mIsOwner;
private final long mMemoryAddr;
- private int mFd;
+ private int mFd = -1;
/**
* Creates a new instance.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3b15456..22329f4 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -16,10 +16,13 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
+
import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
@@ -302,7 +305,7 @@
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
- this(session, name, w, h, format, flags, null, -1, -1);
+ this(session, name, w, h, format, flags, null, INVALID_WINDOW_TYPE, Binder.getCallingUid());
}
public SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ff42ff6..cea3263 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2858,6 +2858,14 @@
*/
static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
+ /**
+ * Flag indicating that when layout is completed we should notify
+ * that the view was entered for autofill purposes. To minimize
+ * showing autofill for views not visible to the user we evaluate
+ * user visibility which cannot be done until the view is laid out.
+ */
+ static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x4000;
+
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -4462,6 +4470,7 @@
sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT;
Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M;
+ Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O;
// In M and newer, our widgets can pass a "hint" value in the size
// for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
@@ -6495,7 +6504,7 @@
if (mParent != null) {
mParent.requestChildFocus(this, this);
- setFocusedInCluster();
+ updateFocusedInCluster(oldFocus, direction);
}
if (mAttachInfo != null) {
@@ -6844,8 +6853,15 @@
if (isAutofillable() && isAttachedToWindow()) {
AutofillManager afm = getAutofillManager();
if (afm != null) {
- if (enter && hasWindowFocus() && isFocused() && isVisibleToUser()) {
- afm.notifyViewEntered(this);
+ if (enter && hasWindowFocus() && isFocused()) {
+ // We have not been laid out yet, hence cannot evaluate
+ // whether this view is visible to the user, we will do
+ // the evaluation once layout is complete.
+ if (!isLaidOut()) {
+ mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
+ } else if (isVisibleToUser()) {
+ afm.notifyViewEntered(this);
+ }
} else if (!hasWindowFocus() || !isFocused()) {
afm.notifyViewExited(this);
}
@@ -9911,22 +9927,47 @@
* @hide
*/
public final void setFocusedInCluster() {
- View top = findKeyboardNavigationCluster();
- if (top == this) {
+ setFocusedInCluster(findKeyboardNavigationCluster());
+ }
+
+ private void setFocusedInCluster(View cluster) {
+ if (this instanceof ViewGroup) {
+ ((ViewGroup) this).mFocusedInCluster = null;
+ }
+ if (cluster == this) {
return;
}
ViewParent parent = mParent;
View child = this;
while (parent instanceof ViewGroup) {
- ((ViewGroup) parent).setFocusedInCluster(child);
- if (parent == top) {
- return;
+ ((ViewGroup) parent).mFocusedInCluster = child;
+ if (parent == cluster) {
+ break;
}
child = (View) parent;
parent = parent.getParent();
}
}
+ private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) {
+ if (oldFocus != null) {
+ View oldCluster = oldFocus.findKeyboardNavigationCluster();
+ View cluster = findKeyboardNavigationCluster();
+ if (oldCluster != cluster) {
+ // Going from one cluster to another, so save last-focused.
+ // This covers cluster jumps because they are always FOCUS_DOWN
+ oldFocus.setFocusedInCluster(oldCluster);
+ if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) {
+ // This is a result of ordered navigation so consider navigation through
+ // the previous cluster "complete" and clear its last-focused memory.
+ if (oldFocus.mParent instanceof ViewGroup) {
+ ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus);
+ }
+ }
+ }
+ }
+ }
+
/**
* Returns whether this View should receive focus when the focus is restored for the view
* hierarchy containing this view.
@@ -19304,6 +19345,11 @@
mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
+
+ if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
+ mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
+ notifyEnterOrExitForAutoFillIfNeeded(true);
+ }
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 18c1b8c..50593f2 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -142,7 +142,7 @@
// that is or contains a default-focus view.
private View mDefaultFocus;
// The last child of this ViewGroup which held focus within the current cluster
- private View mFocusedInCluster;
+ View mFocusedInCluster;
/**
* A Transformation used when drawing children, to
@@ -806,10 +806,6 @@
return mDefaultFocus != null || super.hasDefaultFocus();
}
- void setFocusedInCluster(View child) {
- mFocusedInCluster = child;
- }
-
/**
* Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
* it.
@@ -825,8 +821,11 @@
ViewParent parent = this;
do {
((ViewGroup) parent).mFocusedInCluster = null;
+ if (parent == top) {
+ break;
+ }
parent = parent.getParent();
- } while (parent != top && parent instanceof ViewGroup);
+ } while (parent instanceof ViewGroup);
}
@Override
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8445b37..3f91476 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -743,6 +743,12 @@
public static final int LAST_SYSTEM_WINDOW = 2999;
/**
+ * @hide
+ * Used internally when there is no suitable type available.
+ */
+ public static final int INVALID_WINDOW_TYPE = -1;
+
+ /**
* Return true if the window type is an alert window.
*
* @param type The window type.
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 1f3be84..32fae73 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -140,4 +140,14 @@
@WorkerThread
LinksInfo getLinks(
@NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales);
+
+ /**
+ * Logs a TextClassifier event.
+ *
+ * @param source the text classifier used to generate this event
+ * @param event the text classifier related event
+ * @hide
+ */
+ @WorkerThread
+ default void logEvent(String source, String event) {}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7362c70..5f72fc7 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -40,6 +40,7 @@
import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
import java.io.File;
@@ -77,6 +78,8 @@
private final Context mContext;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
private final Object mSmartSelectionLock = new Object();
@GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
private Map<Locale, String> mModelFilePaths;
@@ -105,7 +108,8 @@
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
- final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
+ final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end)
+ .setLogSource(LOG_TAG);
final SmartSelection.ClassificationResult[] results =
smartSelection.classifyText(
string, start, end,
@@ -173,6 +177,13 @@
return TextClassifier.NO_OP.getLinks(text, linkMask, defaultLocales);
}
+ @Override
+ public void logEvent(String source, String event) {
+ if (LOG_TAG.equals(source)) {
+ mMetricsLogger.count(event, 1);
+ }
+ }
+
private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
synchronized (mSmartSelectionLock) {
localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 3172c13..9a66693 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -34,13 +34,16 @@
private final int mEndIndex;
@NonNull private final EntityConfidence<String> mEntityConfidence;
@NonNull private final List<String> mEntities;
+ @NonNull private final String mLogSource;
private TextSelection(
- int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence) {
+ int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence,
+ @NonNull String logSource) {
mStartIndex = startIndex;
mEndIndex = endIndex;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
mEntities = mEntityConfidence.getEntities();
+ mLogSource = logSource;
}
/**
@@ -87,6 +90,14 @@
return mEntityConfidence.getConfidenceScore(entity);
}
+ /**
+ * Returns a tag for the source classifier used to generate this result.
+ * @hide
+ */
+ public String getSourceClassifier() {
+ return mLogSource;
+ }
+
@Override
public String toString() {
return String.format("TextSelection {%d, %d, %s}",
@@ -102,6 +113,7 @@
private final int mEndIndex;
@NonNull private final EntityConfidence<String> mEntityConfidence =
new EntityConfidence<>();
+ @NonNull private String mLogSource = "";
/**
* Creates a builder used to build {@link TextSelection} objects.
@@ -131,10 +143,19 @@
}
/**
+ * Sets a tag for the source classifier used to generate this result.
+ * @hide
+ */
+ Builder setLogSource(@NonNull String logSource) {
+ mLogSource = Preconditions.checkNotNull(logSource);
+ return this;
+ }
+
+ /**
* Builds and returns {@link TextSelection} object.
*/
public TextSelection build() {
- return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence);
+ return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence, mLogSource);
}
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b0d6395..bb658c1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3925,6 +3925,8 @@
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ getSelectionActionModeHelper().onSelectionAction();
+
if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
return true;
}
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 16a1087..89182b0 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -56,13 +56,14 @@
private TextClassification mTextClassification;
private AsyncTask mTextClassificationAsyncTask;
- private final SelectionInfo mSelectionInfo = new SelectionInfo();
+ private final SelectionTracker mSelectionTracker;
SelectionActionModeHelper(@NonNull Editor editor) {
mEditor = Preconditions.checkNotNull(editor);
final TextView textView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
textView.getTextClassifier(), textView.getText(), 0, 1, textView.getTextLocales());
+ mSelectionTracker = new SelectionTracker(textView.getTextClassifier());
}
public void startActionModeAsync(boolean adjustSelection) {
@@ -99,8 +100,13 @@
}
}
+ public void onSelectionAction() {
+ mSelectionTracker.onSelectionAction(mTextClassificationHelper.getClassifierTag());
+ }
+
public boolean resetSelection(int textIndex) {
- if (mSelectionInfo.resetSelection(textIndex, mEditor)) {
+ if (mSelectionTracker.resetSelection(
+ textIndex, mEditor, mTextClassificationHelper.getClassifierTag())) {
invalidateActionModeAsync();
return true;
}
@@ -113,7 +119,7 @@
}
public void onDestroyActionMode() {
- mSelectionInfo.onSelectionDestroyed();
+ mSelectionTracker.onSelectionDestroyed();
cancelAsyncTask();
}
@@ -137,7 +143,7 @@
private void startActionMode(@Nullable SelectionResult result) {
final TextView textView = mEditor.getTextView();
final CharSequence text = textView.getText();
- mSelectionInfo.setOriginalSelection(
+ mSelectionTracker.setOriginalSelection(
textView.getSelectionStart(), textView.getSelectionEnd());
if (result != null && text instanceof Spannable) {
Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
@@ -151,7 +157,8 @@
controller.show();
}
if (result != null) {
- mSelectionInfo.onSelectionStarted(result.mStart, result.mEnd);
+ mSelectionTracker.onSelectionStarted(
+ result.mStart, result.mEnd, mTextClassificationHelper.getClassifierTag());
}
}
mEditor.setRestartActionModeOnNextRefresh(false);
@@ -165,7 +172,9 @@
actionMode.invalidate();
}
final TextView textView = mEditor.getTextView();
- mSelectionInfo.onSelectionUpdated(textView.getSelectionStart(), textView.getSelectionEnd());
+ mSelectionTracker.onSelectionUpdated(
+ textView.getSelectionStart(), textView.getSelectionEnd(),
+ mTextClassificationHelper.getClassifierTag());
mTextClassificationAsyncTask = null;
}
@@ -177,49 +186,111 @@
}
/**
- * Holds information about the selection and uses it to decide on whether or not to update
- * the selection when resetSelection is called.
- * The expected UX here is to allow the user to select a word inside of the "smart selection" on
- * a single tap.
+ * Tracks and logs smart selection changes.
+ * It is important to trigger this object's methods at the appropriate event so that it tracks
+ * smart selection events appropriately.
*/
- private static final class SelectionInfo {
+ private static final class SelectionTracker {
+
+ // Log event: Smart selection happened.
+ private static final String LOG_EVENT_MULTI_SELECTION =
+ "textClassifier_multiSelection";
+
+ // Log event: Smart selection acted upon.
+ private static final String LOG_EVENT_MULTI_SELECTION_ACTION =
+ "textClassifier_multiSelection_action";
+
+ // Log event: Smart selection was reset to original selection.
+ private static final String LOG_EVENT_MULTI_SELECTION_RESET =
+ "textClassifier_multiSelection_reset";
+
+ // Log event: Smart selection was user modified.
+ private static final String LOG_EVENT_MULTI_SELECTION_MODIFIED =
+ "textClassifier_multiSelection_modified";
+
+ private final TextClassifier mClassifier;
private int mOriginalStart;
private int mOriginalEnd;
private int mSelectionStart;
private int mSelectionEnd;
- private boolean mResetOriginal;
+ private boolean mSmartSelectionActive;
+ SelectionTracker(TextClassifier classifier) {
+ mClassifier = classifier;
+ }
+
+ /**
+ * Called to initialize the original selection before smart selection is triggered.
+ */
public void setOriginalSelection(int selectionStart, int selectionEnd) {
mOriginalStart = selectionStart;
mOriginalEnd = selectionEnd;
- mResetOriginal = false;
+ mSmartSelectionActive = false;
}
- public void onSelectionStarted(int selectionStart, int selectionEnd) {
- // Set the reset flag to true if the selection changed.
+ /**
+ * Called when selection action mode is started.
+ * If the selection indices are different from the original selection indices, we have a
+ * smart selection.
+ */
+ public void onSelectionStarted(int selectionStart, int selectionEnd, String logTag) {
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
- mResetOriginal = mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+ // If the started selection is different from the original selection, we have a
+ // smart selection.
+ mSmartSelectionActive =
+ mSelectionStart != mOriginalStart || mSelectionEnd != mOriginalEnd;
+ if (mSmartSelectionActive) {
+ mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION);
+ }
}
- public void onSelectionUpdated(int selectionStart, int selectionEnd) {
- // If the selection did not change, maintain the reset state. Otherwise, disable reset.
- mResetOriginal &= selectionStart == mSelectionStart && selectionEnd == mSelectionEnd;
+ /**
+ * Called when selection bounds change.
+ */
+ public void onSelectionUpdated(int selectionStart, int selectionEnd, String logTag) {
+ final boolean selectionChanged =
+ selectionStart != mSelectionStart || selectionEnd != mSelectionEnd;
+ if (selectionChanged) {
+ if (mSmartSelectionActive) {
+ mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_MODIFIED);
+ }
+ mSmartSelectionActive = false;
+ }
}
+ /**
+ * Called when the selection action mode is destroyed.
+ */
public void onSelectionDestroyed() {
- mResetOriginal = false;
+ mSmartSelectionActive = false;
}
- public boolean resetSelection(int textIndex, Editor editor) {
+ /**
+ * Logs if the action was taken on a smart selection.
+ */
+ public void onSelectionAction(String logTag) {
+ if (mSmartSelectionActive) {
+ mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_ACTION);
+ }
+ }
+
+ /**
+ * Returns true if the current smart selection should be reset to normal selection based on
+ * information that has been recorded about the original selection and the smart selection.
+ * The expected UX here is to allow the user to select a word inside of the smart selection
+ * on a single tap.
+ */
+ public boolean resetSelection(int textIndex, Editor editor, String logTag) {
final CharSequence text = editor.getTextView().getText();
- if (mResetOriginal
+ if (mSmartSelectionActive
&& textIndex >= mSelectionStart && textIndex <= mSelectionEnd
&& text instanceof Spannable) {
// Only allow a reset once.
- mResetOriginal = false;
+ mSmartSelectionActive = false;
+ mClassifier.logEvent(logTag, LOG_EVENT_MULTI_SELECTION_RESET);
return editor.selectCurrentWord();
}
return false;
@@ -301,6 +372,7 @@
/** End index relative to mText. */
private int mSelectionEnd;
private LocaleList mLocales;
+ private String mClassifierTag = "";
/** Trimmed text starting from mTrimStart in mText. */
private CharSequence mTrimmedText;
@@ -364,9 +436,14 @@
mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
mSelectionStart = Math.max(0, sel.getSelectionStartIndex() + mTrimStart);
mSelectionEnd = Math.min(mText.length(), sel.getSelectionEndIndex() + mTrimStart);
+ mClassifierTag = sel.getSourceClassifier();
return classifyText();
}
+ String getClassifierTag() {
+ return mClassifierTag;
+ }
+
private void trimText() {
mTrimStart = Math.max(0, mSelectionStart - TRIM_DELTA);
final int referenceEnd = Math.min(mText.length(), mSelectionEnd + TRIM_DELTA);
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index fef85da..797cf2b 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -40,6 +40,7 @@
public static String UPDATES = "UPDATES";
public static String NETWORK_STATUS = "NETWORK_STATUS";
public static String NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static String NETWORK_AVAILABLE = "NETWORK_AVAILABLE";
public static String VPN = "VPN";
public static String DEVICE_ADMIN = "DEVICE_ADMIN";
public static String ALERTS = "ALERTS";
@@ -99,6 +100,11 @@
channelsList.add(networkAlertsChannel);
channelsList.add(new NotificationChannel(
+ NETWORK_AVAILABLE,
+ context.getString(R.string.notification_channel_network_available),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
VPN,
context.getString(R.string.notification_channel_vpn),
NotificationManager.IMPORTANCE_LOW));
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a89427d..186b63a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -9819,10 +9819,9 @@
}
});
- // TODO: STOPSHIP, remove the "true" below after b/34961340 is fixed
- if (DEBUG_ENERGY_CPU || true) {
- Slog.d(TAG, "Reading cpu stats took " + (mClocks.elapsedRealtime() - startTimeMs) +
- " ms");
+ final long elapse = (mClocks.elapsedRealtime() - startTimeMs);
+ if (DEBUG_ENERGY_CPU || (elapse >= 100)) {
+ Slog.d(TAG, "Reading cpu stats took " + elapse + " ms");
}
if (mOnBatteryInternal && numWakelocks > 0) {
diff --git a/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java b/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
index b5915aa..aa56e93 100644
--- a/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
+++ b/core/java/com/android/internal/os/KernelMemoryBandwidthStats.java
@@ -8,6 +8,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.BufferedReader;
+import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
@@ -24,14 +25,25 @@
public class KernelMemoryBandwidthStats {
private static final String TAG = "KernelMemoryBandwidthStats";
- final protected LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
private static final String mSysfsFile = "/sys/kernel/memory_state_time/show_stat";
private static final boolean DEBUG = false;
+ protected final LongSparseLongArray mBandwidthEntries = new LongSparseLongArray();
+ private boolean mStatsDoNotExist = false;
+
public void updateStats() {
+ if (mStatsDoNotExist) {
+ // Skip reading.
+ return;
+ }
+
StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
try (BufferedReader reader = new BufferedReader(new FileReader(mSysfsFile))) {
parseStats(reader);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "No kernel memory bandwidth stats available");
+ mBandwidthEntries.clear();
+ mStatsDoNotExist = true;
} catch (IOException e) {
Slog.e(TAG, "Failed to read memory bandwidth: " + e.getMessage());
mBandwidthEntries.clear();
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 56f68d4..5aea2b7 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -168,8 +168,8 @@
}
}
-static void android_os_Parcel_writeNative(JNIEnv* env, jclass clazz, jlong nativePtr, jobject data,
- jint offset, jint length)
+static void android_os_Parcel_writeByteArray(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jobject data, jint offset, jint length)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel == NULL) {
@@ -350,6 +350,28 @@
return ret;
}
+static jboolean android_os_Parcel_readByteArray(JNIEnv* env, jclass clazz, jlong nativePtr,
+ jobject dest, jint destLen)
+{
+ jboolean ret = JNI_FALSE;
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel == NULL) {
+ return ret;
+ }
+
+ int32_t len = parcel->readInt32();
+ if (len >= 0 && len <= (int32_t)parcel->dataAvail() && len == destLen) {
+ jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)dest, 0);
+ if (ar) {
+ const void* data = parcel->readInplace(len);
+ memcpy(ar, data, len);
+ env->ReleasePrimitiveArrayCritical((jarray)dest, ar, 0);
+ ret = JNI_TRUE;
+ }
+ }
+ return ret;
+}
+
static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr)
{
jbyteArray ret = NULL;
@@ -761,7 +783,7 @@
// @FastNative
{"nativeRestoreAllowFds", "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
- {"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeNative},
+ {"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeByteArray},
{"nativeWriteBlob", "(J[BII)V", (void*)android_os_Parcel_writeBlob},
// @FastNative
{"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
@@ -776,6 +798,7 @@
{"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
+ {"nativeReadByteArray", "(J[BI)Z", (void*)android_os_Parcel_readByteArray},
{"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob},
// @FastNative
{"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt},
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ea40fd5..8b73daf 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -503,6 +503,7 @@
SettingProto demo_user_setup_complete = 165;
SettingProto instant_apps_enabled = 166;
SettingProto device_paired = 167;
+ SettingProto notification_badging = 168;
}
message SystemSettingsProto {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 44ddd0e..be53f2c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1010,6 +1010,9 @@
<!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
<bool name="config_intrusiveNotificationLed">false</bool>
+ <!-- De we do icon badges? Used to decide if there should be a disable option-->
+ <bool name="config_notificationBadging">true</bool>
+
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8fc57b1..21ab4c3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -629,6 +629,9 @@
<!-- Text shown when viewing channel settings for notifications related to network alerts -->
<string name="notification_channel_network_alerts">Network alerts</string>
+ <!-- Text shown when viewing the channel settings for notification about open nearby wireless networks. -->
+ <string name="notification_channel_network_available">Network available</string>
+
<!-- Text shown when viewing channel settings for notifications related to vpn status -->
<string name="notification_channel_vpn">VPN status</string>
@@ -2993,6 +2996,17 @@
<!-- If there is ever a ringtone set for some setting, but that ringtone can no longer be resolved, t his is shown instead. For example, if the ringtone was on a SD card and it had been removed, this woudl be shown for ringtones on that SD card. -->
<string name="ringtone_unknown">Unknown</string>
+ <!-- A notification is shown when there are open wireless networks nearby. This is the notification's title. -->
+ <plurals name="wifi_available">
+ <item quantity="one">Wi-Fi network available</item>
+ <item quantity="other">Wi-Fi networks available</item>
+ </plurals>
+ <!-- A notification is shown when there are open wireless networks nearby. This is the notification's message. -->
+ <plurals name="wifi_available_detailed">
+ <item quantity="one">Open Wi-Fi network available</item>
+ <item quantity="other">Open Wi-Fi networks available</item>
+ </plurals>
+
<!-- A notification is shown when a wifi captive portal network is detected. This is the notification's title. -->
<string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6ceea9c..16e933a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1867,6 +1867,8 @@
<java-symbol type="layout" name="safe_mode" />
<java-symbol type="layout" name="simple_list_item_2_single_choice" />
<java-symbol type="layout" name="app_error_dialog" />
+ <java-symbol type="plurals" name="wifi_available" />
+ <java-symbol type="plurals" name="wifi_available_detailed" />
<java-symbol type="string" name="accessibility_binding_label" />
<java-symbol type="string" name="adb_active_notification_message" />
<java-symbol type="string" name="adb_active_notification_title" />
@@ -2095,6 +2097,7 @@
<java-symbol type="string" name="config_wifi_tether_enable" />
<java-symbol type="integer" name="config_wifi_wakeup_available" />
<java-symbol type="bool" name="config_intrusiveNotificationLed" />
+ <java-symbol type="bool" name="config_notificationBadging" />
<java-symbol type="dimen" name="preference_fragment_padding_bottom" />
<java-symbol type="dimen" name="preference_fragment_padding_side" />
<java-symbol type="drawable" name="expander_ic_maximized" />
@@ -2986,6 +2989,7 @@
<java-symbol type="string" name="notification_channel_updates" />
<java-symbol type="string" name="notification_channel_network_status" />
<java-symbol type="string" name="notification_channel_network_alerts" />
+ <java-symbol type="string" name="notification_channel_network_available" />
<java-symbol type="string" name="notification_channel_vpn" />
<java-symbol type="string" name="notification_channel_device_admin" />
<java-symbol type="string" name="notification_channel_alerts" />
diff --git a/core/tests/coretests/src/android/content/pm/AppCacheTest.java b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
index 1567046..15dbddf 100644
--- a/core/tests/coretests/src/android/content/pm/AppCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
@@ -25,11 +25,11 @@
import android.os.ServiceManager;
import android.os.StatFs;
import android.os.UserHandle;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import java.io.File;
@@ -48,14 +48,14 @@
public final long WAIT_TIME_INCR=10*1000;
private static final long THRESHOLD=5;
private static final long ACTUAL_THRESHOLD=10;
-
+
@Override
protected void setUp() throws Exception {
super.setUp();
if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
cleanUpCacheDirectory();
}
-
+
void cleanUpDirectory(File pDir, String dirName) {
File testDir = new File(pDir, dirName);
if(!testDir.exists()) {
@@ -72,13 +72,13 @@
}
testDir.delete();
}
-
+
void cleanUpCacheDirectory() {
File testDir = mContext.getCacheDir();
if(!testDir.exists()) {
return;
}
-
+
String fList[] = testDir.list();
if(fList == null) {
testDir.delete();
@@ -93,7 +93,7 @@
}
}
}
-
+
@SmallTest
public void testDeleteAllCacheFiles() {
String testName="testDeleteAllCacheFiles";
@@ -160,9 +160,9 @@
+(blks1-blks3));
}
}
-
+
/**
- * This method opens an output file writes to it, opens the same file as an input
+ * This method opens an output file writes to it, opens the same file as an input
* stream, reads the contents and verifies the data that was written earlier can be read
*/
public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
@@ -180,7 +180,7 @@
failStr(e.getMessage());
} catch (IOException e) {
failStr(e.getMessage());
- }
+ }
int count = pFileOut.getBytes().length;
byte[] buffer = new byte[count];
try {
@@ -194,8 +194,8 @@
}
String str = new String(buffer);
assertEquals(str, pFileOut);
- }
-
+ }
+
/*
* This test case verifies that output written to a file
* using Context.openFileOutput has executed successfully.
@@ -215,7 +215,7 @@
failStr(e);
}
}
-
+
@SmallTest
public void testAppCacheCreateFile() {
String fileName = "testFile1.txt";
@@ -225,7 +225,7 @@
openOutFileInAppFilesDir(file, fileOut);
cleanUpCacheDirectory();
}
-
+
@MediumTest
public void testAppCreateCacheFiles() {
File cacheDir = mContext.getCacheDir();
@@ -261,7 +261,7 @@
}
}
}
-
+
byte[] getBuffer() {
String sbuffer = "a";
for(int i = 0; i < 10; i++) {
@@ -360,7 +360,7 @@
}
assertTrue("Files should have been removed", removedFlag);
}
-
+
//createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
byte buffer[] = getBuffer();
@@ -439,7 +439,7 @@
}
}
}
-
+
class PackageDataObserver extends IPackageDataObserver.Stub {
public boolean retValue = false;
private boolean doneFlag = false;
@@ -455,11 +455,11 @@
return doneFlag;
}
}
-
+
IPackageManager getPm() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
-
+
boolean invokePMDeleteAppCacheFiles() throws Exception {
try {
String packageName = mContext.getPackageName();
@@ -485,7 +485,7 @@
return false;
}
}
-
+
boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
try {
String packageName = mContext.getPackageName();
@@ -512,7 +512,7 @@
}
}
- boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r,
+ boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r,
PendingIntent pi) throws Exception {
try {
// Spin lock waiting for call back
@@ -536,7 +536,7 @@
return false;
}
}
-
+
@LargeTest
public void testDeleteAppCacheFiles() throws Exception {
String testName="testDeleteAppCacheFiles";
@@ -551,7 +551,7 @@
public boolean retValue = false;
public PackageStats stats;
private boolean doneFlag = false;
-
+
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
synchronized(this) {
@@ -565,7 +565,7 @@
return doneFlag;
}
}
-
+
public PackageStats invokePMGetPackageSizeInfo() throws Exception {
try {
String packageName = mContext.getPackageName();
@@ -593,7 +593,7 @@
return null;
}
}
-
+
@SmallTest
public void testGetPackageSizeInfo() throws Exception {
String testName="testGetPackageSizeInfo";
@@ -603,7 +603,7 @@
if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+
", cache="+stats.cacheSize);
}
-
+
@SmallTest
public void testGetSystemSharedLibraryNames() throws Exception {
try {
@@ -615,17 +615,17 @@
}
} catch (RemoteException e) {
fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
- }
+ }
}
-
+
class FreeStorageReceiver extends BroadcastReceiver {
public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
private boolean doneFlag = false;
-
+
public boolean isDone() {
return doneFlag;
}
-
+
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase(ACTION_FREE)) {
@@ -637,7 +637,7 @@
}
}
}
-
+
// TODO: flaky test, omit from LargeTest for now
//@LargeTest
public void testFreeStorage() throws Exception {
@@ -664,10 +664,10 @@
if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
assertEquals(receiver.getResultCode(), 1);
mContext.unregisterReceiver(receiver);
- // Verify result
+ // Verify result
verifyTestFiles1(cacheDir, "testtmpdir", 5);
}
-
+
/* utility method used to create observer and check async call back from PackageManager.
* ClearApplicationUserData
*/
@@ -696,7 +696,7 @@
return false;
}
}
-
+
void verifyUserDataCleared(File pDir) {
if(localLOGV) Log.i(TAG, "Verifying "+pDir);
if(pDir == null) {
@@ -717,7 +717,7 @@
fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
}
}
-
+
File getDataDir() {
try {
ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0,
@@ -727,7 +727,8 @@
throw new RuntimeException("Pacakge manager dead", e);
}
}
-
+
+ @Suppress
@LargeTest
public void testClearApplicationUserDataWithTestData() throws Exception {
File cacheDir = mContext.getCacheDir();
@@ -740,14 +741,16 @@
//confirm files dont exist
verifyUserDataCleared(getDataDir());
}
-
+
+ @Suppress
@SmallTest
public void testClearApplicationUserDataWithNoTestData() throws Exception {
assertTrue(invokePMClearApplicationUserData());
//confirm files dont exist
verifyUserDataCleared(getDataDir());
}
-
+
+ @Suppress
@LargeTest
public void testClearApplicationUserDataNoObserver() throws Exception {
getPm().clearApplicationUserData(mContext.getPackageName(), null, UserHandle.myUserId());
@@ -756,5 +759,5 @@
//confirm files dont exist
verifyUserDataCleared(getDataDir());
}
-
+
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 86ab3dc..19d2a31 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -45,6 +45,7 @@
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="bluetooth" />
<group gid="wakelock" />
+ <group gid="uhid" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
@@ -181,9 +182,6 @@
<allow-in-power-save package="com.android.cellbroadcastreceiver" />
<allow-in-power-save package="com.android.shell" />
- <!-- STOPSHIP(b/36856786): Revert this once it is fixed properly -->
- <allow-in-power-save package="com.google.android.apps.enterprise.dmagent" />
-
<!-- These are the packages that are white-listed to be able to run as system user -->
<system-user-whitelisted-app package="com.android.settings" />
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 2a2e14b..0301f2e 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -49,6 +49,8 @@
public class Canvas extends BaseCanvas {
/** @hide */
public static boolean sCompatibilityRestore = false;
+ /** @hide */
+ public static boolean sCompatibilitySetBitmap = false;
/** @hide */
public long getNativeCanvasWrapper() {
@@ -172,6 +174,11 @@
throw new RuntimeException("Can't set a bitmap device on a HW accelerated canvas");
}
+ Matrix preservedMatrix = null;
+ if (bitmap != null && sCompatibilitySetBitmap) {
+ preservedMatrix = getMatrix();
+ }
+
if (bitmap == null) {
nSetBitmap(mNativeCanvasWrapper, null);
mDensity = Bitmap.DENSITY_NONE;
@@ -185,6 +192,10 @@
mDensity = bitmap.mDensity;
}
+ if (preservedMatrix != null) {
+ setMatrix(preservedMatrix);
+ }
+
mBitmap = bitmap;
}
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 2771ade..60e3845 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -44,8 +44,7 @@
};
class BagAttributeFinder
- : public BackTrackingAttributeFinder<BagAttributeFinder,
- const ResTable::bag_entry*> {
+ : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
public:
BagAttributeFinder(const ResTable::bag_entry* start,
const ResTable::bag_entry* end)
@@ -76,8 +75,7 @@
uint32_t def_style_bag_type_set_flags = 0;
if (def_style_attr != 0) {
Res_value value;
- if (theme->getAttribute(def_style_attr, &value,
- &def_style_bag_type_set_flags) >= 0) {
+ if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
if (value.dataType == Res_value::TYPE_REFERENCE) {
def_style_res = value.data;
}
@@ -127,18 +125,14 @@
ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
value.data);
}
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- const ResTable::bag_entry* const def_style_entry =
- def_style_attr_finder.Find(cur_ident);
+ } else {
+ const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
if (def_style_entry != def_style_end) {
block = def_style_entry->stringBlock;
type_set_flags = def_style_type_set_flags;
value = def_style_entry->map.value;
if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
@@ -146,29 +140,24 @@
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ssize_t new_block = theme->resolveAttributeReference(
- &value, block, &resid, &type_set_flags, &config);
+ ssize_t new_block =
+ theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
if (new_block >= 0) block = new_block;
if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- } else {
+ } else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find
// it in the theme!
- ssize_t new_block =
- theme->getAttribute(cur_ident, &value, &type_set_flags);
+ ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
if (new_block >= 0) {
if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_block = res.resolveReference(&value, new_block, &resid,
- &type_set_flags, &config);
+ new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
if (new_block >= 0) block = new_block;
if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
@@ -184,8 +173,7 @@
}
if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
- value.dataType, value.data);
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
}
// Write the final value back to Java.
@@ -198,7 +186,8 @@
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
- if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+ if (out_indices != nullptr &&
+ (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
indices_idx++;
out_indices[indices_idx] = ii;
}
@@ -247,8 +236,7 @@
ssize_t idx = xml_parser->indexOfStyle();
if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
if (value.dataType == value.TYPE_ATTRIBUTE) {
- if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) <
- 0) {
+ if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
value.dataType = Res_value::TYPE_NULL;
}
}
@@ -318,41 +306,34 @@
// We found the attribute we were looking for.
xml_parser->getAttributeValue(xml_attr_idx, &value);
if (kDebugStyles) {
- ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the style class values looking for the requested
- // attribute.
- const ResTable::bag_entry* const style_attr_entry =
- style_attr_finder.Find(cur_ident);
+ if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ // Walk through the style class values looking for the requested attribute.
+ const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
if (style_attr_entry != style_attr_end) {
// We found the attribute we were looking for.
block = style_attr_entry->stringBlock;
type_set_flags = style_type_set_flags;
value = style_attr_entry->map.value;
if (kDebugStyles) {
- ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the default style values looking for the requested
- // attribute.
- const ResTable::bag_entry* const def_style_attr_entry =
- def_style_attr_finder.Find(cur_ident);
+ if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ // Walk through the default style values looking for the requested attribute.
+ const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
if (def_style_attr_entry != def_style_attr_end) {
// We found the attribute we were looking for.
block = def_style_attr_entry->stringBlock;
type_set_flags = style_type_set_flags;
value = def_style_attr_entry->map.value;
if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
@@ -360,35 +341,29 @@
uint32_t resid = 0;
if (value.dataType != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ssize_t new_block = theme->resolveAttributeReference(
- &value, block, &resid, &type_set_flags, &config);
+ ssize_t new_block =
+ theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
if (new_block >= 0) {
block = new_block;
}
if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- } else {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t new_block =
- theme->getAttribute(cur_ident, &value, &type_set_flags);
+ } else if (value.data != Res_value::DATA_NULL_EMPTY) {
+ // If we still don't have a value for this attribute, try to find it in the theme!
+ ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
if (new_block >= 0) {
if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
- new_block = res.resolveReference(&value, new_block, &resid,
- &type_set_flags, &config);
+ new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
if (new_block >= 0) {
block = new_block;
}
if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType,
- value.data);
+ ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
@@ -404,8 +379,7 @@
}
if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident,
- value.dataType, value.data);
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
}
// Write the final value back to Java.
@@ -418,7 +392,7 @@
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
indices_idx++;
// out_indices must NOT be nullptr.
@@ -502,7 +476,8 @@
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
- if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+ if (out_indices != nullptr &&
+ (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
indices_idx++;
out_indices[indices_idx] = ii;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index f661f29b..bab8883 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3538,7 +3538,8 @@
attrRes, bag->map.value.dataType, bag->map.value.data,
curEntry->value.dataType);
}
- if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
+ if (force || (curEntry->value.dataType == Res_value::TYPE_NULL
+ && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) {
curEntry->stringBlock = bag->stringBlock;
curEntry->typeSpecFlags |= bagTypeSpecFlags;
curEntry->value = bag->map.value;
@@ -3674,7 +3675,8 @@
}
ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
return BAD_INDEX;
- } else if (type != Res_value::TYPE_NULL) {
+ } else if (type != Res_value::TYPE_NULL
+ || te.value.data == Res_value::DATA_NULL_EMPTY) {
*outValue = te.value;
return te.stringBlock;
}
@@ -5997,16 +5999,14 @@
char locale[RESTABLE_MAX_LOCALE_LEN];
forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) {
- if (cfg.locale != 0) {
- cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
+ cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
- const auto beginIter = locales->begin();
- const auto endIter = locales->end();
+ const auto beginIter = locales->begin();
+ const auto endIter = locales->end();
- auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
- if (iter == endIter || strcmp(iter->string(), locale) != 0) {
- locales->insertAt(String8(locale), std::distance(beginIter, iter));
- }
+ auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
+ if (iter == endIter || strcmp(iter->string(), locale) != 0) {
+ locales->insertAt(String8(locale), std::distance(beginIter, iter));
}
});
}
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index d8e5abf..fcae53b 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -264,7 +264,7 @@
const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
ASSERT_NE(nullptr, bag_two);
- ASSERT_EQ(5u, bag_two->entry_count);
+ ASSERT_EQ(6u, bag_two->entry_count);
// attr_one is inherited from StyleOne.
EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
@@ -295,6 +295,11 @@
EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
EXPECT_EQ(3u, bag_two->entries[4].value.data);
EXPECT_EQ(0, bag_two->entries[4].cookie);
+
+ EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key);
+ EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data);
+ EXPECT_EQ(0, bag_two->entries[5].cookie);
}
TEST_F(AssetManager2Test, ResolveReferenceToResource) {
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 1ff2ed4..2d73ce8 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -69,8 +69,8 @@
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
- std::array<uint32_t, 4> attrs{
- {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+ std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+ R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
@@ -109,11 +109,21 @@
EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+ // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
+ // as the theme.
+ values_cursor += STYLE_NUM_ENTRIES;
+ EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+ EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+ EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
}
TEST_F(AttributeResolutionXmlTest, XmlParser) {
- std::array<uint32_t, 4> attrs{
- {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+ std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+ R::attr::attr_four, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
@@ -121,7 +131,7 @@
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
- EXPECT_EQ(0u, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
@@ -150,16 +160,24 @@
EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+ values_cursor += STYLE_NUM_ENTRIES;
+ EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(Res_value::DATA_NULL_UNDEFINED, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+ EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+ EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
}
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
- std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
- R::attr::attr_four, R::attr::attr_five}};
+ std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+ R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- std::array<uint32_t, attrs.size()> indices;
+ std::array<uint32_t, attrs.size() + 1> indices;
ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
attrs.size(), values.data(), indices.data());
@@ -167,12 +185,12 @@
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
uint32_t* values_cursor = values.data();
- EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
- EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
- EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(uint32_t(-1), values_cursor[STYLE_ASSET_COOKIE]);
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
- EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+ EXPECT_EQ(0u, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
values_cursor += STYLE_NUM_ENTRIES;
EXPECT_EQ(Res_value::TYPE_STRING, values_cursor[STYLE_TYPE]);
@@ -203,6 +221,20 @@
EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+ // @empty comes from the theme, so it has the same asset cookie and changing configurations flags
+ // as the theme.
+ values_cursor += STYLE_NUM_ENTRIES;
+ EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, values_cursor[STYLE_DATA]);
+ EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
+ EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
+ EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
+ EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
+
+ // The first element of indices contains the number of indices.
+ std::array<uint32_t, 7> expected_indices = {{6u, 0u, 1u, 2u, 3u, 4u, 5u}};
+ EXPECT_EQ(expected_indices, indices);
}
} // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 68527c7..05073a8 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -33,6 +33,7 @@
attr_five = 0x7f010004u,
attr_indirect = 0x7f010005u,
attr_six = 0x7f010006u,
+ attr_empty = 0x7f010007u,
};
};
diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build
index 81f78b1..1ef8e6e 100755
--- a/libs/androidfw/tests/data/styles/build
+++ b/libs/androidfw/tests/data/styles/build
@@ -2,4 +2,5 @@
set -e
-aapt package -F styles.apk -M AndroidManifest.xml -S res -f
+aapt2 compile -o compiled.flata --dir res
+aapt2 link -o styles.apk --manifest AndroidManifest.xml compiled.flata
diff --git a/libs/androidfw/tests/data/styles/res/layout/layout.xml b/libs/androidfw/tests/data/styles/res/layout/layout.xml
index f3aa0f8..2c5e947 100644
--- a/libs/androidfw/tests/data/styles/res/layout/layout.xml
+++ b/libs/androidfw/tests/data/styles/res/layout/layout.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:app="http://schemas.android.com/apk/res-auto"
app:attr_four="?attr/attr_indirect"
- app:attr_three="10" />
-
+ app:attr_three="10"
+ app:attr_one="@empty" />
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index da592f8..3c90317 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -33,6 +33,12 @@
<public type="attr" name="attr_indirect" id="0x7f010005" />
<attr name="attr_indirect" />
+ <public type="attr" name="attr_six" id="0x7f010006" />
+ <attr name="attr_six" />
+
+ <public type="attr" name="attr_empty" id="0x7f010007" />
+ <attr name="attr_empty" />
+
<public type="string" name="string_one" id="0x7f030000" />
<string name="string_one">Hi</string>
@@ -48,11 +54,9 @@
<item name="attr_two">"string"</item>
<item name="attr_three">?attr/attr_indirect</item>
<item name="attr_five">@string/string_one</item>
+ <item name="attr_empty">@empty</item>
</style>
-
- <public type="attr" name="attr_six" id="0x7f010006" />
- <attr name="attr_six" />
-
+
<public type="style" name="StyleThree" id="0x7f020002" />
<style name="StyleThree">
<item name="attr_six">6</item>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index d4ccb83..72abf8f 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index c157a47..a19726c 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1067,7 +1067,7 @@
private void applyLevelLimits() {
int[] sampleRates = null;
Range<Integer> sampleRateRange = null, bitRates = null;
- int maxChannels = 0;
+ int maxChannels = MAX_INPUT_CHANNEL_COUNT;
String mime = mParent.getMimeType();
if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MPEG)) {
@@ -1160,6 +1160,8 @@
if (info.containsKey("max-channel-count")) {
maxInputChannels = Utils.parseIntSafely(
info.getString("max-channel-count"), maxInputChannels);
+ } else if ((mParent.mError & ERROR_UNSUPPORTED) != 0) {
+ maxInputChannels = 0;
}
if (info.containsKey("bitrate-range")) {
bitRates = bitRates.intersect(
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java
deleted file mode 100644
index 74b0c6b..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/LinkAccessibilityHelper.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.accessibility;
-
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.ExploreByTouchHelper;
-import android.text.Layout;
-import android.text.Spanned;
-import android.text.style.ClickableSpan;
-import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.TextView;
-
-import java.util.List;
-
-/**
- * COPIED FROM SETUP WIZARD An accessibility delegate that allows {@link
- * android.text.style.ClickableSpan} to be focused and clicked by accessibility services.
- *
- * <p>Sample usage:
- *
- * <pre>
- * LinkAccessibilityHelper mAccessibilityHelper;
- *
- * private void init() {
- * mAccessibilityHelper = new LinkAccessibilityHelper(myTextView);
- * ViewCompat.setAccessibilityDelegate(myTextView, mLinkHelper);
- * }
- *
- * {@literal @}Override
- * protected boolean dispatchHoverEvent({@literal @}NonNull MotionEvent event) {
- * if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {
- * return true;
- * }
- * return super.dispatchHoverEvent(event);
- * }
- * </pre>
- *
- * @see android.support.v4.widget.ExploreByTouchHelper
- */
-public class LinkAccessibilityHelper extends ExploreByTouchHelper {
-
- private static final String TAG = "LinkAccessibilityHelper";
-
- private final TextView mView;
- private final Rect mTempRect = new Rect();
-
- public LinkAccessibilityHelper(TextView view) {
- super(view);
- mView = view;
- }
-
- @Override
- protected int getVirtualViewAt(float x, float y) {
- final CharSequence text = mView.getText();
- if (text instanceof Spanned) {
- final Spanned spannedText = (Spanned) text;
- final int offset = getOffsetForPosition(mView, x, y);
- ClickableSpan[] linkSpans = spannedText.getSpans(offset, offset, ClickableSpan.class);
- if (linkSpans.length == 1) {
- ClickableSpan linkSpan = linkSpans[0];
- return spannedText.getSpanStart(linkSpan);
- }
- }
- return INVALID_ID;
- }
-
- @Override
- protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
- final CharSequence text = mView.getText();
- if (text instanceof Spanned) {
- final Spanned spannedText = (Spanned) text;
- ClickableSpan[] linkSpans =
- spannedText.getSpans(0, spannedText.length(), ClickableSpan.class);
- for (ClickableSpan span : linkSpans) {
- virtualViewIds.add(spannedText.getSpanStart(span));
- }
- }
- }
-
- @Override
- protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
- final ClickableSpan span = getSpanForOffset(virtualViewId);
- if (span != null) {
- event.setContentDescription(getTextForSpan(span));
- } else {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- event.setContentDescription(mView.getText());
- }
- }
-
- @Override
- protected void onPopulateNodeForVirtualView(
- int virtualViewId, AccessibilityNodeInfoCompat info) {
- final ClickableSpan span = getSpanForOffset(virtualViewId);
- if (span != null) {
- info.setContentDescription(getTextForSpan(span));
- } else {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- info.setContentDescription(mView.getText());
- }
- info.setFocusable(true);
- info.setClickable(true);
- getBoundsForSpan(span, mTempRect);
- if (mTempRect.isEmpty()) {
- Log.e(TAG, "LinkSpan bounds is empty for: " + virtualViewId);
- mTempRect.set(0, 0, 1, 1);
- }
- info.setBoundsInParent(mTempRect);
- info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
- }
-
- @Override
- protected boolean onPerformActionForVirtualView(
- int virtualViewId, int action, Bundle arguments) {
- if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
- ClickableSpan span = getSpanForOffset(virtualViewId);
- if (span != null) {
- span.onClick(mView);
- return true;
- } else {
- Log.e(TAG, "LinkSpan is null for offset: " + virtualViewId);
- }
- }
- return false;
- }
-
- private ClickableSpan getSpanForOffset(int offset) {
- CharSequence text = mView.getText();
- if (text instanceof Spanned) {
- Spanned spannedText = (Spanned) text;
- ClickableSpan[] spans = spannedText.getSpans(offset, offset, ClickableSpan.class);
- if (spans.length == 1) {
- return spans[0];
- }
- }
- return null;
- }
-
- private CharSequence getTextForSpan(ClickableSpan span) {
- CharSequence text = mView.getText();
- if (text instanceof Spanned) {
- Spanned spannedText = (Spanned) text;
- return spannedText.subSequence(
- spannedText.getSpanStart(span), spannedText.getSpanEnd(span));
- }
- return text;
- }
-
- // Find the bounds of a span. If it spans multiple lines, it will only return the bounds for the
- // section on the first line.
- private Rect getBoundsForSpan(ClickableSpan span, Rect outRect) {
- CharSequence text = mView.getText();
- outRect.setEmpty();
- if (text instanceof Spanned) {
- final Layout layout = mView.getLayout();
- if (layout != null) {
- Spanned spannedText = (Spanned) text;
- final int spanStart = spannedText.getSpanStart(span);
- final int spanEnd = spannedText.getSpanEnd(span);
- final float xStart = layout.getPrimaryHorizontal(spanStart);
- final float xEnd = layout.getPrimaryHorizontal(spanEnd);
- final int lineStart = layout.getLineForOffset(spanStart);
- final int lineEnd = layout.getLineForOffset(spanEnd);
- layout.getLineBounds(lineStart, outRect);
- if (lineEnd == lineStart) {
- // If the span is on a single line, adjust both the left and right bounds
- // so outrect is exactly bounding the span.
- outRect.left = (int) Math.min(xStart, xEnd);
- outRect.right = (int) Math.max(xStart, xEnd);
- } else {
- // If the span wraps across multiple lines, only use the first line (as returned
- // by layout.getLineBounds above), and adjust the "start" of outrect to where
- // the span starts, leaving the "end" of outrect at the end of the line.
- // ("start" being left for LTR, and right for RTL)
- if (layout.getParagraphDirection(lineStart) == Layout.DIR_RIGHT_TO_LEFT) {
- outRect.right = (int) xStart;
- } else {
- outRect.left = (int) xStart;
- }
- }
-
- // Offset for padding
- outRect.offset(mView.getTotalPaddingLeft(), mView.getTotalPaddingTop());
- }
- }
- return outRect;
- }
-
- // Compat implementation of TextView#getOffsetForPosition().
-
- private static int getOffsetForPosition(TextView view, float x, float y) {
- if (view.getLayout() == null) return -1;
- final int line = getLineAtCoordinate(view, y);
- return getOffsetAtCoordinate(view, line, x);
- }
-
- private static float convertToLocalHorizontalCoordinate(TextView view, float x) {
- x -= view.getTotalPaddingLeft();
- // Clamp the position to inside of the view.
- x = Math.max(0.0f, x);
- x = Math.min(view.getWidth() - view.getTotalPaddingRight() - 1, x);
- x += view.getScrollX();
- return x;
- }
-
- private static int getLineAtCoordinate(TextView view, float y) {
- y -= view.getTotalPaddingTop();
- // Clamp the position to inside of the view.
- y = Math.max(0.0f, y);
- y = Math.min(view.getHeight() - view.getTotalPaddingBottom() - 1, y);
- y += view.getScrollY();
- return view.getLayout().getLineForVertical((int) y);
- }
-
- private static int getOffsetAtCoordinate(TextView view, int line, float x) {
- x = convertToLocalHorizontalCoordinate(view, x);
- return view.getLayout().getOffsetForHorizontal(line, x);
- }
-}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java b/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java
index da86536..8b9315c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/LinkTextView.java
@@ -16,32 +16,25 @@
package com.android.settingslib.widget;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ViewCompat;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.widget.TextView;
-import com.android.settingslib.accessibility.LinkAccessibilityHelper;
+
/**
- * Copied from setup wizard. This TextView performs two functions. The first is to make it so the
- * link behaves properly and becomes clickable. The second is that it makes the link visible to
- * accessibility services.
+ * Copied from setup wizard. This TextView performed two functions. The first is to make it so the
+ * link behaves properly and becomes clickable. The second was that it made the link visible to
+ * accessibility services, but from O forward support for links is provided natively.
*/
public class LinkTextView extends TextView {
- private LinkAccessibilityHelper mAccessibilityHelper;
-
public LinkTextView(Context context) {
this(context, null);
}
public LinkTextView(Context context, AttributeSet attrs) {
super(context, attrs);
- mAccessibilityHelper = new LinkAccessibilityHelper(this);
- ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
}
@Override
@@ -55,12 +48,4 @@
}
}
}
-
- @Override
- protected boolean dispatchHoverEvent(@NonNull MotionEvent event) {
- if (mAccessibilityHelper.dispatchHoverEvent(event)) {
- return true;
- }
- return super.dispatchHoverEvent(event);
- }
}
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f475361..9309359 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1434,6 +1434,9 @@
dumpSetting(s, p,
Settings.Secure.DEVICE_PAIRED,
SecureSettingsProto.DEVICE_PAIRED);
+ dumpSetting(s, p,
+ Settings.Secure.NOTIFICATION_BADGING,
+ SecureSettingsProto.NOTIFICATION_BADGING);
}
private static void dumpProtoSystemSettingsLocked(
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 69d9de9..e3ef873 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -305,7 +305,6 @@
android:excludeFromRecents="true"
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
- android:screenOrientation="behind"
android:resizeableActivity="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:theme="@style/RecentsTheme.Wallpaper">
diff --git a/packages/SystemUI/res/drawable/stat_sys_cast.xml b/packages/SystemUI/res/drawable/stat_sys_cast.xml
index 4a7cbb3..5228085 100644
--- a/packages/SystemUI/res/drawable/stat_sys_cast.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_cast.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,11 +18,11 @@
android:insetRight="2.5dp">
<vector android:width="17dp"
android:height="17dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="17.0"
+ android:viewportHeight="17.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM38.0,14.0L10.0,14.0l0.0,3.3c7.9,2.6 14.2,8.8 16.7,16.7L38.0,34.0L38.0,14.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0z"/>
+ android:pathData="M0.71,12.75v1.42c0,0.39 0.32,0.71 0.71,0.71h1.42C2.83,13.7 1.88,12.75 0.71,12.75zM0.69,10.67c-0.01,0.36 0.25,0.66 0.6,0.72c1.47,0.26 2.65,1.42 2.9,2.89c0.06,0.34 0.35,0.6 0.7,0.6c0.43,0 0.77,-0.38 0.71,-0.81c-0.34,-2.11 -2,-3.76 -4.11,-4.09C1.08,9.91 0.7,10.24 0.69,10.67zM13.46,4.96H3.54v1.15c2.81,0.91 5.02,3.12 5.93,5.93h3.99V4.96zM0.69,7.81C0.68,8.18 0.95,8.49 1.31,8.53c3.02,0.3 5.44,2.71 5.74,5.72c0.04,0.35 0.34,0.62 0.7,0.62c0.42,0 0.75,-0.36 0.71,-0.78c-0.37,-3.69 -3.3,-6.62 -6.99,-6.98C1.06,7.08 0.7,7.4 0.69,7.81zM14.88,2.12H2.12c-0.78,0 -1.42,0.64 -1.42,1.42v2.12h1.42V3.54h12.75v9.92H9.92v1.42h4.96c0.78,0 1.42,-0.64 1.42,-1.42V3.54C16.29,2.76 15.65,2.12 14.88,2.12z" />
</vector>
</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
index 01e8888..5dcf5c8 100644
--- a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,11 +19,14 @@
<vector
android:width="17.0dp"
android:height="17.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M24.000000,22.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000C28.000000,23.799999 26.200001,22.000000 24.000000,22.000000zM36.000000,26.000000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-6.600000,0.000000 -12.000000,5.400000 -12.000000,12.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-4.400000 3.600000,-8.000000 8.000000,-8.000000s8.000000,3.600000 8.000000,8.000000c0.000000,3.000000 -1.600000,5.500000 -4.000000,6.900000l2.000000,3.500000C33.599998,34.299999 36.000000,30.400000 36.000000,26.000000zM24.000000,6.000000C13.000000,6.000000 4.000000,15.000000 4.000000,26.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-8.800000 7.200000,-16.000000 16.000000,-16.000000s16.000000,7.200000 16.000000,16.000000c0.000000,5.900000 -3.200000,11.100000 -8.000000,13.800000l2.000000,3.500000c6.000000,-3.500000 10.000000,-9.900000 10.000000,-17.299999C44.000000,15.000000 35.000000,6.000000 24.000000,6.000000z"/>
+ android:viewportWidth="18.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateX="0.5"
+ android:translateY="0.5" >
+ <path
+ android:pathData="M8.5,7.79c-0.78,0 -1.42,0.64 -1.42,1.42c0,0.78 0.64,1.42 1.42,1.42s1.42,-0.64 1.42,-1.42C9.92,8.43 9.28,7.79 8.5,7.79zM12.75,9.21c0,-2.35 -1.9,-4.25 -4.25,-4.25c-0.18,0 -0.35,0.01 -0.53,0.03C6.11,5.22 4.58,6.7 4.3,8.55c-0.23,1.52 0.35,2.91 1.36,3.82C6,12.67 6.54,12.6 6.76,12.2c0.17,-0.3 0.1,-0.67 -0.16,-0.89c-0.78,-0.7 -1.12,-1.77 -0.86,-2.79C5.99,7.5 6.78,6.71 7.8,6.46C9.32,6.08 10.86,7 11.25,8.52c0.06,0.23 0.09,0.46 0.09,0.69c0,0.84 -0.36,1.58 -0.94,2.1c-0.25,0.23 -0.33,0.6 -0.16,0.9c0.22,0.38 0.74,0.49 1.06,0.2C12.22,11.6 12.75,10.43 12.75,9.21zM7.63,1.85C4.19,2.24 1.42,5.07 1.1,8.52c-0.26,2.61 0.88,5.15 2.99,6.7c0.36,0.26 0.86,0.15 1.09,-0.23c0.19,-0.32 0.1,-0.74 -0.19,-0.96c-1.7,-1.26 -2.71,-3.38 -2.35,-5.73c0.4,-2.6 2.57,-4.68 5.19,-4.97c3.59,-0.41 6.63,2.4 6.63,5.91c0,1.97 -0.96,3.7 -2.43,4.79c-0.3,0.22 -0.38,0.63 -0.19,0.96c0.22,0.39 0.73,0.49 1.09,0.23c1.9,-1.4 3.03,-3.62 3.03,-5.98C15.94,4.84 12.12,1.34 7.63,1.85z"
+ android:fillColor="#FFFFFFFF"/>
+ </group>
</vector>
</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
index 2de2e36..b3cd455 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,12 +16,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
android:height="18.41dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
- android:fillColor="?attr/fillColor"/>
+ android:viewportWidth="21.2"
+ android:viewportHeight="21.2">
+ <group
+ android:translateX="0.5"
+ android:translateY="2.0">
+ <path
+ android:pathData="M18.79,9.79c-0.32,-0.32 -0.83,-0.32 -1.15,0L16.43,11l-1.21,-1.21c-0.32,-0.32 -0.83,-0.32 -1.15,0L14.06,9.8l0,0c-0.32,0.32 -0.32,0.83 0,1.15l1.21,1.21l-1.21,1.21l0,0c-0.32,0.32 -0.32,0.83 0,1.15l0.01,0.01c0.32,0.32 0.83,0.32 1.15,0l1.21,-1.21l1.21,1.21c0.32,0.32 0.83,0.32 1.15,0c0.32,-0.32 0.32,-0.83 0,-1.15l-1.21,-1.21l1.21,-1.21C19.1,10.64 19.1,10.13 18.79,9.79z"
+ android:fillColor="?attr/fillColor"/>
+ <path
+ android:pathData="M11.69,7.44h6.27L19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56c-1.6,-1.05 -5.04,-2.9 -9.62,-2.9c-4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V7.44z"
+ android:fillColor="?attr/backgroundColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
index 60f7eb6..6c0fad8 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="21.66"
+ android:viewportHeight="20">
+ <group
+ android:translateX="0.74"
+ android:translateY="1.2">
+ <path
+ android:pathData="M19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56 -1.6,-1.05 -5.04,-2.9 -9.62,-2.9 -4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0L19.95,5z"
+ android:fillColor="?attr/backgroundColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
index 144a7c1..2ebbaf2 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,17 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="18.41dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
- android:fillColor="?attr/fillColor"/>
+ android:width="18.41dp"
+ android:height="18.41dp"
+ android:viewportWidth="21.7"
+ android:viewportHeight="21.7">
+ <group
+ android:translateY="2.2"
+ android:translateX="0.75">
+ <path
+ android:pathData="M11.69,7.44h6.27L19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56c-1.6,-1.05 -5.04,-2.9 -9.62,-2.9c-4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V7.44z"
+ android:fillColor="?attr/backgroundColor" />
+ <path
+ android:pathData="M5.02,10.86l4.25,5.21c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V9.14c-0.51,-0.11 -1.05,-0.17 -1.59,-0.17C8.15,8.97 6.37,9.69 5.02,10.86z"
+ android:fillColor="?attr/fillColor" />
+ <path
+ android:pathData="M17.57,12.17l1.21,-1.21c0.32,-0.32 0.32,-0.83 0,-1.17c-0.32,-0.32 -0.83,-0.32 -1.15,0L16.43,11l-1.21,-1.21c-0.32,-0.32 -0.83,-0.32 -1.15,0L14.06,9.8c-0.32,0.32 -0.32,0.83 0,1.15l1.21,1.21l-1.21,1.21c-0.32,0.32 -0.32,0.83 0,1.15l0.01,0.01c0.32,0.32 0.83,0.32 1.15,0l1.21,-1.21l1.21,1.21c0.32,0.32 0.83,0.32 1.15,0c0.32,-0.32 0.32,-0.83 0,-1.15L17.57,12.17z"
+ android:fillColor="?attr/fillColor" />
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
index 554350d..eaead9b 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M13.100000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.500000,6.500000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M13.100000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000z"/>
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="21.66"
+ android:viewportHeight="20.0">
+ <group
+ android:translateX="0.79"
+ android:translateY="1.2">
+ <path
+ android:pathData="M19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56 -1.6,-1.05 -5.04,-2.9 -9.62,-2.9 -4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0L19.95,5z"
+ android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M10.1,8.97c-1.95,0 -3.72,0.72 -5.08,1.9l4.25,5.21c0.42,0.52 1.22,0.52 1.64,0l4.26,-5.22a7.702,7.702 0,0 0,-5.07 -1.89z"
+ android:fillColor="?attr/fillColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
index 6b7f712..809147c 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,17 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="18.41dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.800001,1.9 -1.800001,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
- android:fillColor="?attr/fillColor"/>
+ android:width="18.41dp"
+ android:height="18.41dp"
+ android:viewportWidth="21.7"
+ android:viewportHeight="21.7">
+ <group
+ android:translateX="0.75"
+ android:translateY="2.2" >
+ <path
+ android:pathData="M11.69,7.44h6.27L19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56c-1.6,-1.05 -5.04,-2.9 -9.62,-2.9c-4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V7.44z"
+ android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M10.09,6.44c-2.55,0 -4.88,0.93 -6.68,2.45l5.85,7.18c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V7.44h2.84C13.18,6.8 11.68,6.44 10.09,6.44z"
+ android:fillColor="?attr/fillColor"/>
+ <path
+ android:pathData="M17.57,12.17l1.21,-1.21c0.32,-0.32 0.32,-0.83 0,-1.17c-0.32,-0.32 -0.83,-0.32 -1.15,0L16.43,11l-1.21,-1.21c-0.32,-0.32 -0.83,-0.32 -1.15,0L14.06,9.8c-0.32,0.32 -0.32,0.83 0,1.15l1.21,1.21l-1.21,1.21c-0.32,0.32 -0.32,0.83 0,1.15l0.01,0.01c0.32,0.32 0.83,0.32 1.15,0l1.21,-1.21l1.21,1.21c0.32,0.32 0.83,0.32 1.15,0c0.32,-0.32 0.32,-0.83 0,-1.15L17.57,12.17z"
+ android:fillColor="?attr/fillColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
index 2c2465a..6d4fb77 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M13.000000,22.000000l7.600000,-9.400000C20.299999,12.400000 17.400000,10.000000 13.000000,10.000000s-7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+android:width="18.41dp"
+android:height="17dp"
+android:viewportWidth="21.86"
+android:viewportHeight="20.19">
+ <group
+ android:translateX="0.85"
+ android:translateY="1.4" >
+ <path
+ android:pathData="M19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56 -1.6,-1.05 -5.04,-2.9 -9.62,-2.9 -4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0L19.95,5z"
+ android:fillColor="?attr/backgroundColor" />
+ <path
+ android:pathData="M10.09,6.44c-2.55,0 -4.88,0.93 -6.68,2.45l5.85,7.18c0.42,0.52 1.22,0.52 1.64,0l5.86,-7.19a10.284,10.284 0,0 0,-6.67 -2.44z"
+ android:fillColor="?attr/fillColor" />
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
index d34b4de..4c479c0 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,15 +16,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
android:height="18.41dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/fillColor"/>
- <path
- android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/backgroundColor"/>
- <path
- android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
- android:fillColor="?attr/fillColor"/>
+ android:viewportWidth="21.7"
+ android:viewportHeight="21.7">
+ <group
+ android:translateX="0.75"
+ android:translateY="2.3" >
+ <path
+ android:pathData="M11.69,7.44h6.27L19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56c-1.6,-1.05 -5.04,-2.9 -9.62,-2.9c-4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0l0.78,-0.96V7.44z"
+ android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M10.08,4.75c-2.96,0 -5.66,1.06 -7.74,2.82l6.93,8.5c0.21,0.26 0.51,0.39 0.82,0.39c0.22,0 0.44,-0.07 0.63,-0.2c0.07,-0.05 0.14,-0.11 0.2,-0.19l0.78,-0.96V7.44h5.98C15.6,5.77 12.96,4.75 10.08,4.75z"
+ android:fillColor="?attr/fillColor"/>
+ <path
+ android:pathData="M17.57,12.17l1.21,-1.21c0.32,-0.32 0.32,-0.83 0,-1.17c-0.32,-0.32 -0.83,-0.32 -1.15,0L16.43,11l-1.21,-1.21c-0.32,-0.32 -0.83,-0.32 -1.15,0L14.06,9.8c-0.32,0.32 -0.32,0.83 0,1.15l1.21,1.21l-1.21,1.21c-0.32,0.32 -0.32,0.83 0,1.15l0.01,0.01c0.32,0.32 0.83,0.32 1.15,0l1.21,-1.21l1.21,1.21c0.32,0.32 0.83,0.32 1.15,0c0.32,-0.32 0.32,-0.83 0,-1.15L17.57,12.17z"
+ android:fillColor="?attr/fillColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
index 7d0f756..6c96300 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M13.000000,22.000000l9.200000,-11.400000c-0.400000,-0.300000 -3.900000,-3.200000 -9.200000,-3.200000s-8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="21.80"
+ android:viewportHeight="20.1">
+ <group
+ android:translateX="0.81"
+ android:translateY="1.29" >
+ <path
+ android:pathData="M19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56 -1.6,-1.05 -5.04,-2.9 -9.62,-2.9 -4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0L19.95,5z"
+ android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M10.08,4.75c-2.96,0 -5.66,1.06 -7.74,2.82l6.93,8.5c0.21,0.26 0.51,0.39 0.82,0.39 0.23,0 0.46,-0.07 0.65,-0.22 -0.02,0.02 -0.04,0.03 -0.07,0.05 0.09,-0.06 0.17,-0.13 0.24,-0.22l6.93,-8.5c-2.09,-1.74 -4.8,-2.82 -7.76,-2.82z"
+ android:fillColor="?attr/fillColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
index 7d1bfe1..8fb7a7b 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,14 +14,16 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="18.41dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/singleToneColor"/>
- <path
- android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
- android:fillColor="?attr/singleToneColor"/>
+ android:width="18.41dp"
+ android:height="18.41dp"
+ android:viewportWidth="21.95"
+ android:viewportHeight="21.65">
+ <group
+ android:translateX="0.90"
+ android:translateY="2.25"
+ >
+ <path
+ android:pathData="M11.69,15.12l-0.78,0.96c-0.43,0.52 -1.22,0.52 -1.64,0L0.24,5c-0.4,-0.49 -0.29,-1.22 0.23,-1.56c1.59,-1.05 5.03,-2.9 9.62,-2.9c4.59,0 8.02,1.85 9.62,2.9c0.53,0.35 0.63,1.08 0.23,1.56l-1.99,2.44h-6.27V15.12zM18.79,9.79c-0.32,-0.32 -0.83,-0.32 -1.15,0L16.43,11l-1.21,-1.21c-0.32,-0.32 -0.83,-0.32 -1.15,0L14.06,9.8l0,0c-0.32,0.32 -0.32,0.83 0,1.15l1.21,1.21l-1.21,1.21l0,0c-0.32,0.32 -0.32,0.83 0,1.15l0.01,0.01c0.32,0.32 0.83,0.32 1.15,0l1.21,-1.21l1.21,1.21c0.32,0.32 0.83,0.32 1.15,0c0.32,-0.32 0.32,-0.83 0,-1.15l-1.21,-1.21l1.21,-1.21C19.1,10.64 19.1,10.13 18.79,9.79z"
+ android:fillColor="?attr/singleToneColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
index a7e213f..bc3fdb5 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="21.75"
+ android:viewportHeight="20.0">
+ <group
+ android:translateX="0.80"
+ android:translateY="1.25">
+ <path
+ android:pathData="M19.95,5c0.4,-0.49 0.3,-1.22 -0.23,-1.56 -1.6,-1.05 -5.04,-2.9 -9.62,-2.9 -4.59,0 -8.03,1.85 -9.62,2.9C-0.05,3.78 -0.16,4.51 0.24,5l9.02,11.08c0.42,0.52 1.22,0.52 1.64,0L19.95,5z"
+ android:fillColor="?attr/singleToneColor"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index bdc0871..da2d38f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -73,7 +73,8 @@
mTouchHandler.onActivityPinned();
mMediaController.onActivityPinned();
mMenuController.onActivityPinned();
- mNotificationController.onActivityPinned(packageName);
+ mNotificationController.onActivityPinned(packageName,
+ true /* deferUntilAnimationEnds */);
SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
}
@@ -104,6 +105,7 @@
mTouchHandler.setTouchEnabled(true);
mTouchHandler.onPinnedStackAnimationEnded();
mMenuController.onPinnedStackAnimationEnded();
+ mNotificationController.onPinnedStackAnimationEnded();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
index 53746e2..696fdbc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
@@ -60,6 +60,9 @@
private PipMotionHelper mMotionHelper;
+ // Used when building a deferred notification
+ private String mDeferredNotificationPackageName;
+
private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
@Override
public void onOpChanged(String op, String packageName) {
@@ -87,10 +90,47 @@
mMotionHelper = motionHelper;
}
- public void onActivityPinned(String packageName) {
+ public void onActivityPinned(String packageName, boolean deferUntilAnimationEnds) {
// Clear any existing notification
mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+ if (deferUntilAnimationEnds) {
+ mDeferredNotificationPackageName = packageName;
+ } else {
+ showNotificationForApp(mDeferredNotificationPackageName);
+ }
+
+ // Register for changes to the app ops setting for this package while it is in PiP
+ registerAppOpsListener(packageName);
+ }
+
+ public void onPinnedStackAnimationEnded() {
+ if (mDeferredNotificationPackageName != null) {
+ showNotificationForApp(mDeferredNotificationPackageName);
+ mDeferredNotificationPackageName = null;
+ }
+ }
+
+ public void onActivityUnpinned(ComponentName topPipActivity) {
+ // Unregister for changes to the previously PiP'ed package
+ unregisterAppOpsListener();
+
+ // Reset the deferred notification package
+ mDeferredNotificationPackageName = null;
+
+ if (topPipActivity != null) {
+ // onActivityUnpinned() is only called after the transition is complete, so we don't
+ // need to defer until the animation ends to update the notification
+ onActivityPinned(topPipActivity.getPackageName(), false /* deferUntilAnimationEnds */);
+ } else {
+ mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+ }
+ }
+
+ /**
+ * Builds and shows the notification for the given app.
+ */
+ private void showNotificationForApp(String packageName) {
// Build a new notification
final Notification.Builder builder =
new Notification.Builder(mContext, NotificationChannels.GENERAL)
@@ -105,20 +145,6 @@
// Show the new notification
mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
}
-
- // Register for changes to the app ops setting for this package while it is in PiP
- registerAppOpsListener(packageName);
- }
-
- public void onActivityUnpinned(ComponentName topPipActivity) {
- // Unregister for changes to the previously PiP'ed package
- unregisterAppOpsListener();
-
- if (topPipActivity != null) {
- onActivityPinned(topPipActivity.getPackageName());
- } else {
- mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 7518527a..e457d72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -77,6 +77,9 @@
BatteryMeterView battery = findViewById(R.id.battery);
battery.setForceShowPercent(true);
+ // Don't show the Wi-Fi indicator here, because it is shown just below in the tile.
+ SignalClusterView signalCluster = findViewById(R.id.signal_cluster);
+ signalCluster.setForceBlockWifi();
mActivityStarter = Dependency.get(ActivityStarter.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 90c65580..8f24ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -767,17 +767,22 @@
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
mIsInMinimizeInteraction = true;
- if (minimized && (mCurrentAnimator == null || !mCurrentAnimator.isRunning())) {
+ if (minimized && (mCurrentAnimator == null || !mCurrentAnimator.isRunning())
+ && (mDividerPositionBeforeMinimized <= 0 || !mAdjustedForIme)) {
mDividerPositionBeforeMinimized = getCurrentPosition();
}
mMinimizedSnapAlgorithm = null;
mDockedStackMinimized = minimized;
initializeSnapAlgorithm();
- stopDragging(getCurrentPosition(), minimized ?
- mMinimizedSnapAlgorithm.getMiddleTarget() :
- mSnapAlgorithm.calculateNonDismissingSnapTarget(
+ stopDragging(minimized
+ ? mDividerPositionBeforeMinimized
+ : getCurrentPosition(),
+ minimized
+ ? mMinimizedSnapAlgorithm.getMiddleTarget()
+ : mSnapAlgorithm.calculateNonDismissingSnapTarget(
mDividerPositionBeforeMinimized),
animDuration, Interpolators.FAST_OUT_SLOW_IN, 0);
+ setAdjustedForIme(false, animDuration);
}
if (!minimized) {
mBackground.animate().withEndAction(mResetBackgroundRunnable);
@@ -820,6 +825,9 @@
.setDuration(animDuration)
.start();
mAdjustedForIme = adjustedForIme;
+ if (mHomeStackResizable && adjustedForIme) {
+ mDividerPositionBeforeMinimized = getCurrentPosition();
+ }
}
private void resetBackground() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 30ff30f..be221bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -341,14 +341,12 @@
public void appTransitionPending(boolean forced) {
synchronized (mLock) {
- mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
}
}
public void appTransitionCancelled() {
synchronized (mLock) {
- mHandler.removeMessages(MSG_APP_TRANSITION_CANCELLED);
mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
}
}
@@ -359,7 +357,6 @@
public void appTransitionStarting(long startTime, long duration, boolean forced) {
synchronized (mLock) {
- mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
Pair.create(startTime, duration)).sendToTarget();
}
@@ -368,7 +365,6 @@
@Override
public void appTransitionFinished() {
synchronized (mLock) {
- mHandler.removeMessages(MSG_APP_TRANSITION_FINISHED);
mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index dc254f9..28a858c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -120,6 +120,7 @@
private boolean mBlockWifi;
private boolean mBlockEthernet;
private boolean mActivityEnabled;
+ private boolean mForceBlockWifi;
public SignalClusterView(Context context) {
this(context, null);
@@ -151,6 +152,16 @@
updateActivityEnabled();
}
+ public void setForceBlockWifi() {
+ mForceBlockWifi = true;
+ mBlockWifi = true;
+ if (isAttachedToWindow()) {
+ // Re-register to get new callbacks.
+ mNetworkController.removeCallback(this);
+ mNetworkController.addCallback(this);
+ }
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
@@ -167,7 +178,7 @@
mBlockAirplane = blockAirplane;
mBlockMobile = blockMobile;
mBlockEthernet = blockEthernet;
- mBlockWifi = blockWifi;
+ mBlockWifi = blockWifi || mForceBlockWifi;
// Re-register to get new callbacks.
mNetworkController.removeCallback(this);
mNetworkController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 96e0731..27fc6a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2514,7 +2514,7 @@
if (animate) {
mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount);
mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
mDarkAnimator.start();
} else {
setDarkAmount(darkAmount);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index b2712ff..aad4431 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -4365,7 +4365,7 @@
}
addWidgetLocked(id);
}
- if (id.provider.info != null) {
+ if (id.provider != null && id.provider.info != null) {
stashProviderRestoreUpdateLocked(id.provider,
restoredId, id.appWidgetId);
} else {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 0999580..41a78a7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -20,6 +20,7 @@
import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.bundleToString;
@@ -397,6 +398,21 @@
}
}
+ // Called by Shell command.
+ public int getMaxPartitions() {
+ synchronized (mLock) {
+ return sPartitionMaxCount;
+ }
+ }
+
+ // Called by Shell command.
+ public void setMaxPartitions(int max) {
+ Slog.i(TAG, "setMaxPartitions(): " + max);
+ synchronized (mLock) {
+ sPartitionMaxCount = max;
+ }
+ }
+
private void setDebugLocked(boolean debug) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
@@ -628,6 +644,7 @@
pw.print("Debug mode: "); pw.println(oldDebug);
pw.print("Verbose mode: "); pw.println(sVerbose);
pw.print("Disabled users: "); pw.println(mDisabledUsers);
+ pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
final int size = mServicesCache.size();
pw.print("Cached services: ");
if (size == 0) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 1b9c86e..f3de557 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -70,9 +70,15 @@
pw.println(" get log_level ");
pw.println(" Gets the Autofill log level (off | debug | verbose).");
pw.println("");
+ pw.println(" get max_partitions");
+ pw.println(" Gets the maximum number of partitions per session.");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
+ pw.println(" set max_partitions number");
+ pw.println(" Sets the maximum number of partitions per session.");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" List all pending sessions.");
pw.println("");
@@ -86,9 +92,33 @@
}
private int requestGet(PrintWriter pw) {
- if (!isNextArgLogLevel(pw, "get")) {
- return -1;
+ final String what = getNextArgRequired();
+ switch(what) {
+ case "log_level":
+ return getLogLevel(pw);
+ case "max_partitions":
+ return getMaxPartitions(pw);
+ default:
+ pw.println("Invalid set: " + what);
+ return -1;
}
+ }
+
+ private int requestSet(PrintWriter pw) {
+ final String what = getNextArgRequired();
+
+ switch(what) {
+ case "log_level":
+ return setLogLevel(pw);
+ case "max_partitions":
+ return setMaxPartitions();
+ default:
+ pw.println("Invalid set: " + what);
+ return -1;
+ }
+ }
+
+ private int getLogLevel(PrintWriter pw) {
final int logLevel = mService.getLogLevel();
switch (logLevel) {
case AutofillManager.FLAG_ADD_CLIENT_VERBOSE:
@@ -106,11 +136,8 @@
}
}
- private int requestSet(PrintWriter pw) {
- if (!isNextArgLogLevel(pw, "set")) {
- return -1;
- }
- final String logLevel = getNextArg();
+ private int setLogLevel(PrintWriter pw) {
+ final String logLevel = getNextArgRequired();
switch (logLevel.toLowerCase()) {
case "verbose":
mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
@@ -127,6 +154,16 @@
}
}
+ private int getMaxPartitions(PrintWriter pw) {
+ pw.println(mService.getMaxPartitions());
+ return 0;
+ }
+
+ private int setMaxPartitions() {
+ mService.setMaxPartitions(Integer.parseInt(getNextArgRequired()));
+ return 0;
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index ffcde8d..0281f73 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -26,16 +26,23 @@
/**
* Defines a logging flag that can be dynamically changed at runtime using
- * {@code cmd autofill debug [on|off]}.
+ * {@code cmd autofill set log_level debug}.
*/
public static boolean sDebug = false;
/**
* Defines a logging flag that can be dynamically changed at runtime using
- * {@code cmd autofill verbose [on|off]}.
+ * {@code cmd autofill set log_level verbose}.
*/
public static boolean sVerbose = false;
+ /**
+ * Maximum number of partitions that can be allowed in a session.
+ *
+ * <p>Can be modified using {@code cmd autofill set max_partitions}.
+ */
+ static int sPartitionMaxCount = 10;
+
private Helper() {
throw new UnsupportedOperationException("contains static members only");
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index a12ebb2..35f4fae 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -27,11 +27,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.ICancellationSignal;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.service.autofill.AutofillService;
import android.service.autofill.FillRequest;
@@ -43,6 +45,7 @@
import android.text.format.DateUtils;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.HandlerCaller;
import com.android.server.FgThread;
@@ -63,6 +66,9 @@
// How long after the last interaction with the service we would unbind
private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+ // How long after we make a remote request to a fill service we timeout
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
+
private final Context mContext;
private final ComponentName mComponentName;
@@ -413,12 +419,18 @@
private static final class PendingFillRequest extends PendingRequest {
private final Object mLock = new Object();
+
private final WeakReference<RemoteFillService> mWeakService;
private final FillRequest mRequest;
private final IFillCallback mCallback;
private ICancellationSignal mCancellation;
+
+ @GuardedBy("mLock")
private boolean mCancelled;
+ @GuardedBy("mLock")
+ private boolean mCompleted;
+
public PendingFillRequest(FillRequest request, RemoteFillService service) {
mRequest = request;
mWeakService = new WeakReference<>(service);
@@ -443,8 +455,15 @@
@Override
public void onSuccess(FillResponse response) {
+ synchronized (mLock) {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ }
RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
+ service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
getCallingUid(), request.getFlags(), response);
}
@@ -452,13 +471,29 @@
@Override
public void onFailure(CharSequence message) {
+ synchronized (mLock) {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ }
RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
+ service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestFailure(
PendingFillRequest.this, message);
}
}
};
+ service.mHandler.getHandler().postAtTime(() -> {
+ cancel();
+ try {
+ mCallback.onFailure(null);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }, PendingFillRequest.this,
+ SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
}
@Override
@@ -496,10 +531,15 @@
}
private static final class PendingSaveRequest extends PendingRequest {
+ private final Object mLock = new Object();
+
private final WeakReference<RemoteFillService> mWeakService;
private final SaveRequest mRequest;
private final ISaveCallback mCallback;
+ @GuardedBy("mLock")
+ private boolean mCompleted;
+
public PendingSaveRequest(@NonNull SaveRequest request,
@NonNull RemoteFillService service) {
mRequest = request;
@@ -507,8 +547,16 @@
mCallback = new ISaveCallback.Stub() {
@Override
public void onSuccess() {
+ synchronized (mLock) {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ }
+ cancel();
RemoteFillService service = mWeakService.get();
if (service != null) {
+ service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
service.dispatchOnSaveRequestSuccess(
PendingSaveRequest.this);
}
@@ -516,13 +564,29 @@
@Override
public void onFailure(CharSequence message) {
+ synchronized (mLock) {
+ if (mCompleted) {
+ return;
+ }
+ mCompleted = true;
+ }
RemoteFillService service = mWeakService.get();
if (service != null) {
+ service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
service.dispatchOnSaveRequestFailure(
PendingSaveRequest.this, message);
}
}
};
+ service.mHandler.getHandler().postAtTime(() -> {
+ cancel();
+ try {
+ mCallback.onFailure(null);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }, PendingSaveRequest.this,
+ SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ef5cdd1..4746ee9 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sPartitionMaxCount;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.ViewState.STATE_AUTOFILLED;
import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
@@ -162,6 +163,7 @@
@GuardedBy("mLock")
private boolean mIsSaving;
+
/**
* Receiver of assist data from the app's {@link Activity}.
*/
@@ -933,7 +935,6 @@
}
}
- private static final int PARTITION_MAX_COUNT = 64;
/**
* Determines if a new partition should be started for an id.
*
@@ -947,8 +948,9 @@
}
final int numResponses = mResponses.size();
- if (numResponses >= PARTITION_MAX_COUNT) {
- Slog.e(TAG, "Cannot create more than 64 partitions. Not creating a new partition.");
+ if (numResponses >= sPartitionMaxCount) {
+ Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id
+ + " reached maximum of " + sPartitionMaxCount);
return false;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8555851..54b02a8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -91,6 +91,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -3951,7 +3952,8 @@
synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
- throw new IllegalArgumentException("Too many NetworkRequests filed");
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS);
}
mUidToNetworkRequestCount.put(mUid, networkRequests);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1ed46a0..5e03508 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1493,12 +1493,13 @@
mAm.updateOomAdjLocked(r.binding.service.app, false);
}
}
+
+ mAm.updateOomAdjLocked();
+
} finally {
Binder.restoreCallingIdentity(origId);
}
- mAm.updateOomAdjLocked();
-
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c6699b6..3541a3a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1466,6 +1466,20 @@
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
boolean mForceResizableActivities;
+ /**
+ * Flag that indicates if multi-window is enabled.
+ *
+ * For any particular form of multi-window to be enabled, generic multi-window must be enabled
+ * in {@link com.android.internal.R.bool.config_supportsMultiWindow} config or
+ * {@link Settings.Global#DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES} development option set.
+ * At least one of the forms of multi-window must be enabled in order for this flag to be
+ * initialized to 'true'.
+ *
+ * @see #mSupportsSplitScreenMultiWindow
+ * @see #mSupportsFreeformWindowManagement
+ * @see #mSupportsPictureInPicture
+ * @see #mSupportsMultiDisplay
+ */
boolean mSupportsMultiWindow;
boolean mSupportsSplitScreenMultiWindow;
boolean mSupportsFreeformWindowManagement;
@@ -4578,7 +4592,7 @@
mAppSwitchesAllowedTime = 0;
}
}
- int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null,
+ int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions, null);
return ret;
}
@@ -7484,11 +7498,12 @@
}
@Override
- public int sendIntentSender(IIntentSender target, int code, Intent intent, String resolvedType,
+ public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code,
+ Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
if (target instanceof PendingIntentRecord) {
return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType,
- finishedReceiver, requiredPermission, options);
+ whitelistToken, finishedReceiver, requiredPermission, options);
} else {
if (intent == null) {
// Weird case: someone has given us their own custom IIntentSender, and now
@@ -7500,7 +7515,8 @@
intent = new Intent(Intent.ACTION_MAIN);
}
try {
- target.send(code, intent, resolvedType, null, requiredPermission, options);
+ target.send(code, intent, resolvedType, whitelistToken, null,
+ requiredPermission, options);
} catch (RemoteException e) {
}
// Platform code can rely on getting a result back when the send is done, but if
@@ -7797,11 +7813,15 @@
// be guarded by permission checking.
int getUidState(int uid) {
synchronized (this) {
- UidRecord uidRec = mActiveUids.get(uid);
- return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+ return getUidStateLocked(uid);
}
}
+ int getUidStateLocked(int uid) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec == null ? ActivityManager.PROCESS_STATE_NONEXISTENT : uidRec.curProcState;
+ }
+
@Override
public boolean isInMultiWindowMode(IBinder token) {
final long origId = Binder.clearCallingIdentity();
@@ -13361,8 +13381,12 @@
public void setRenderThread(int tid) {
synchronized (this) {
ProcessRecord proc;
+ int pid = Binder.getCallingPid();
+ if (pid == Process.myPid()) {
+ demoteSystemServerRenderThread(tid);
+ return;
+ }
synchronized (mPidsSelfLocked) {
- int pid = Binder.getCallingPid();
proc = mPidsSelfLocked.get(pid);
if (proc != null && proc.renderThreadTid == 0 && tid > 0) {
// ensure the tid belongs to the process
@@ -13395,6 +13419,16 @@
}
}
+ /**
+ * We only use RenderThread in system_server to store task snapshots to the disk, which should
+ * happen in the background. Thus, demote render thread from system_server to a lower priority.
+ *
+ * @param tid the tid of the RenderThread
+ */
+ private void demoteSystemServerRenderThread(int tid) {
+ setThreadPriority(tid, Process.THREAD_PRIORITY_BACKGROUND);
+ }
+
@Override
public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
@@ -13900,16 +13934,23 @@
mAlwaysFinishActivities = alwaysFinishActivities;
mSupportsLeanbackOnly = supportsLeanbackOnly;
mForceResizableActivities = forceResizable;
- if (supportsMultiWindow || forceResizable) {
+ final boolean multiWindowFormEnabled = freeformWindowManagement
+ || supportsSplitScreenMultiWindow
+ || supportsPictureInPicture
+ || supportsMultiDisplay;
+ if ((supportsMultiWindow || forceResizable) && multiWindowFormEnabled) {
mSupportsMultiWindow = true;
- mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
+ mSupportsFreeformWindowManagement = freeformWindowManagement;
+ mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
+ mSupportsPictureInPicture = supportsPictureInPicture;
+ mSupportsMultiDisplay = supportsMultiDisplay;
} else {
mSupportsMultiWindow = false;
mSupportsFreeformWindowManagement = false;
+ mSupportsSplitScreenMultiWindow = false;
+ mSupportsPictureInPicture = false;
+ mSupportsMultiDisplay = false;
}
- mSupportsSplitScreenMultiWindow = supportsSplitScreenMultiWindow;
- mSupportsPictureInPicture = supportsPictureInPicture;
- mSupportsMultiDisplay = supportsMultiDisplay;
mWindowManager.setForceResizableTasks(mForceResizableActivities);
mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
// This happens before any activities are started, so we can change global configuration
@@ -23617,12 +23658,13 @@
}
@Override
- public void setPendingIntentWhitelistDuration(IIntentSender target, long duration) {
+ public void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
+ long duration) {
if (!(target instanceof PendingIntentRecord)) {
Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
return;
}
- ((PendingIntentRecord) target).setWhitelistDurationLocked(duration);
+ ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index dab122f..6eae9e6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -22,11 +22,8 @@
import android.app.IActivityContainer;
import android.app.IActivityController;
import android.app.IActivityManager;
-import android.app.IInstrumentationWatcher;
import android.app.IStopUserCallback;
-import android.app.Instrumentation;
import android.app.ProfilerInfo;
-import android.app.UiAutomationConnection;
import android.app.WaitResult;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
@@ -37,7 +34,6 @@
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.IPackageManager;
-import android.content.pm.InstrumentationInfo;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 5c57be2..f13dad7 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -2180,7 +2180,7 @@
void setRequestedOrientation(int requestedOrientation) {
if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen
- && appInfo.targetSdkVersion >= O) {
+ && appInfo.targetSdkVersion > O) {
throw new IllegalStateException("Only fullscreen activities can request orientation");
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f51635d..ca9d119 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4719,7 +4719,7 @@
checkEmbeddedAllowedInner(userId, pendingIntent.key.requestIntent,
pendingIntent.key.requestResolvedType);
- return pendingIntent.sendInner(0, null, null, null, null, null, null, 0,
+ return pendingIntent.sendInner(0, null, null, null, null, null, null, null, 0,
FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 7ba67c5..6eca3fa 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -32,6 +32,7 @@
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Slog;
import android.util.TimeUtils;
@@ -51,7 +52,7 @@
final WeakReference<PendingIntentRecord> ref;
boolean sent = false;
boolean canceled = false;
- private long whitelistDuration = 0;
+ private ArrayMap<IBinder, Long> whitelistDuration;
private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
String stringName;
@@ -194,8 +195,19 @@
ref = new WeakReference<PendingIntentRecord>(this);
}
- void setWhitelistDurationLocked(long duration) {
- this.whitelistDuration = duration;
+ void setWhitelistDurationLocked(IBinder whitelistToken, long duration) {
+ if (duration > 0) {
+ if (whitelistDuration == null) {
+ whitelistDuration = new ArrayMap<>();
+ }
+ whitelistDuration.put(whitelistToken, duration);
+ } else if (whitelistDuration != null) {
+ whitelistDuration.remove(whitelistToken);
+ if (whitelistDuration.size() <= 0) {
+ whitelistDuration = null;
+ }
+
+ }
this.stringName = null;
}
@@ -219,19 +231,20 @@
return listeners;
}
- public void send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
- String requiredPermission, Bundle options) {
- sendInner(code, intent, resolvedType, finishedReceiver,
- requiredPermission, null, null, 0, 0, 0, options, null);
- }
-
- public int sendWithResult(int code, Intent intent, String resolvedType,
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- return sendInner(code, intent, resolvedType, finishedReceiver,
+ sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
requiredPermission, null, null, 0, 0, 0, options, null);
}
- int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
+ public int sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+ return sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
+ requiredPermission, null, null, 0, 0, 0, options, null);
+ }
+
+ int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+ IIntentReceiver finishedReceiver,
String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
if (intent != null) intent.setDefusable(true);
@@ -276,20 +289,29 @@
final long origId = Binder.clearCallingIdentity();
- if (whitelistDuration > 0) {
- StringBuilder tag = new StringBuilder(64);
- tag.append("pendingintent:");
- UserHandle.formatUid(tag, callingUid);
- tag.append(":");
- if (finalIntent.getAction() != null) {
- tag.append(finalIntent.getAction());
- } else if (finalIntent.getComponent() != null) {
- finalIntent.getComponent().appendShortString(tag);
- } else if (finalIntent.getData() != null) {
- tag.append(finalIntent.getData());
+ if (whitelistDuration != null) {
+ Long duration = whitelistDuration.get(whitelistToken);
+ if (duration != null) {
+ int procState = owner.getUidState(callingUid);
+ if (!ActivityManager.isProcStateBackground(procState)) {
+ StringBuilder tag = new StringBuilder(64);
+ tag.append("pendingintent:");
+ UserHandle.formatUid(tag, callingUid);
+ tag.append(":");
+ if (finalIntent.getAction() != null) {
+ tag.append(finalIntent.getAction());
+ } else if (finalIntent.getComponent() != null) {
+ finalIntent.getComponent().appendShortString(tag);
+ } else if (finalIntent.getData() != null) {
+ tag.append(finalIntent.getData());
+ }
+ owner.tempWhitelistForPendingIntentLocked(callingPid,
+ callingUid, uid, duration, tag.toString());
+ } else {
+ Slog.w(TAG, "Not doing whitelist " + this + ": caller state="
+ + procState);
+ }
}
- owner.tempWhitelistForPendingIntentLocked(callingPid,
- callingUid, uid, whitelistDuration, tag.toString());
}
boolean sendFinish = finishedReceiver != null;
@@ -425,10 +447,17 @@
pw.print(prefix); pw.print("sent="); pw.print(sent);
pw.print(" canceled="); pw.println(canceled);
}
- if (whitelistDuration != 0) {
+ if (whitelistDuration != null) {
pw.print(prefix);
pw.print("whitelistDuration=");
- TimeUtils.formatDuration(whitelistDuration, pw);
+ for (int i = 0; i < whitelistDuration.size(); i++) {
+ if (i != 0) {
+ pw.print(", ");
+ }
+ pw.print(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
+ pw.print(":");
+ TimeUtils.formatDuration(whitelistDuration.valueAt(i), pw);
+ }
pw.println();
}
if (mCancelCallbacks != null) {
@@ -451,9 +480,16 @@
sb.append(key.packageName);
sb.append(' ');
sb.append(key.typeName());
- if (whitelistDuration > 0) {
+ if (whitelistDuration != null) {
sb.append( " (whitelist: ");
- TimeUtils.formatDuration(whitelistDuration, sb);
+ for (int i = 0; i < whitelistDuration.size(); i++) {
+ if (i != 0) {
+ sb.append(",");
+ }
+ sb.append(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
+ sb.append(":");
+ TimeUtils.formatDuration(whitelistDuration.valueAt(i), sb);
+ }
sb.append(")");
}
sb.append('}');
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index e6edaf1..1bd2085 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -41,9 +41,10 @@
if (DBG) Slog.d(TAG, "missing config");
return null;
}
+ boolean userWantsBadges = mConfig.badgingEnabled(record.sbn.getUser());
boolean appCanShowBadge =
mConfig.canShowBadge(record.sbn.getPackageName(), record.sbn.getUid());
- if (!appCanShowBadge) {
+ if (!userWantsBadges || !appCanShowBadge) {
record.setShowBadge(false);
} else {
record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7dcd6cd..9cd0dff 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -344,6 +344,7 @@
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
+ private static final IBinder WHITELIST_TOKEN = new Binder();
private RankingHandler mRankingHandler;
private long mLastOverRateLogTime;
private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
@@ -926,6 +927,8 @@
};
private final class SettingsObserver extends ContentObserver {
+ private final Uri NOTIFICATION_BADGING_URI
+ = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
private final Uri NOTIFICATION_RATE_LIMIT_URI
@@ -937,6 +940,8 @@
void observe() {
ContentResolver resolver = getContext().getContentResolver();
+ resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
+ false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
@@ -962,6 +967,9 @@
mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
}
+ if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
+ mRankingHelper.updateBadgingEnabled();
+ }
}
}
@@ -983,6 +991,7 @@
public NotificationManagerService(Context context) {
super(context);
+ Notification.processWhitelistToken = WHITELIST_TOKEN;
}
// TODO - replace these methods with a single VisibleForTesting constructor
@@ -1818,6 +1827,12 @@
}
@Override
+ public boolean onlyHasDefaultChannel(String pkg, int uid) {
+ enforceSystemOrSystemUI("onlyHasDefaultChannel");
+ return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
+ }
+
+ @Override
public int getDeletedChannelCount(String pkg, int uid) {
enforceSystemOrSystemUI("getDeletedChannelCount");
return mRankingHelper.getDeletedChannelCount(pkg, uid);
@@ -3256,7 +3271,8 @@
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
- am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
+ am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
+ WHITELIST_TOKEN, duration);
}
}
}
@@ -3794,17 +3810,11 @@
updateLightsLocked();
}
if (buzz || beep || blink) {
- if (((record.getSuppressedVisualEffects()
- & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
- if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
- } else {
- MetricsLogger.action(record.getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_ALERT)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
- EventLogTags.writeNotificationAlert(key,
- buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
- }
+ MetricsLogger.action(record.getLogMaker()
+ .setCategory(MetricsEvent.NOTIFICATION_ALERT)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
+ EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
}
}
@@ -4025,6 +4035,7 @@
private void handleRankingSort(Message msg) {
if (!(msg.obj instanceof Boolean)) return;
+ if (mRankingHelper == null) return;
boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
synchronized (mNotificationLock) {
final int N = mNotificationList.size();
@@ -4072,6 +4083,8 @@
| (mZenModeHelper.shouldSuppressWhenScreenOn()
? SUPPRESSED_EFFECT_SCREEN_ON : 0);
record.setSuppressedVisualEffects(suppressed);
+ } else {
+ record.setSuppressedVisualEffects(0);
}
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 4d19b52..36da04d 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -18,6 +18,7 @@
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.content.pm.ParceledListSlice;
+import android.os.UserHandle;
import java.util.Collection;
@@ -27,6 +28,7 @@
int getImportance(String packageName, int uid);
void setShowBadge(String packageName, int uid, boolean showBadge);
boolean canShowBadge(String packageName, int uid);
+ boolean badgingEnabled(UserHandle userHandle);
Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7758516..e83d453 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -21,6 +21,8 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -33,10 +35,14 @@
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import org.json.JSONArray;
import org.json.JSONException;
@@ -48,11 +54,13 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -89,6 +97,7 @@
private final Context mContext;
private final RankingHandler mRankingHandler;
private final PackageManager mPm;
+ private SparseBooleanArray mBadgingEnabled;
public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
NotificationUsageStats usageStats, String[] extractorNames) {
@@ -98,6 +107,8 @@
mPreliminaryComparator = new NotificationComparator(mContext);
+ updateBadgingEnabled();
+
final int N = extractorNames.length;
mSignalExtractors = new NotificationSignalExtractor[N];
for (int i = 0; i < N; i++) {
@@ -301,7 +312,8 @@
private void createDefaultChannelIfNeeded(Record r) throws NameNotFoundException {
if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- // Already exists
+ r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(
+ mContext.getString(R.string.default_notification_channel_label));
return;
}
@@ -574,12 +586,8 @@
updateConfig();
}
- private void clearLockedFields(NotificationChannel channel) {
- int clearMask = 0;
- for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
- clearMask |= NotificationChannel.LOCKABLE_FIELDS[i];
- }
- channel.lockFields(~clearMask);
+ void clearLockedFields(NotificationChannel channel) {
+ channel.unlockFields(channel.getUserLockedFields());
}
@Override
@@ -597,6 +605,7 @@
if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
}
+ lockFieldsForUpdate(channel, updatedChannel);
r.channels.put(updatedChannel.getId(), updatedChannel);
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
@@ -770,6 +779,21 @@
return new ParceledListSlice<>(channels);
}
+ /**
+ * True for pre-O apps that only have the default channel, or pre O apps that have no
+ * channels yet. This method will create the default channel for pre-O apps that don't have it.
+ * Should never be true for O+ targeting apps, but that's enforced on boot/when an app
+ * upgrades.
+ */
+ public boolean onlyHasDefaultChannel(String pkg, int uid) {
+ Record r = getOrCreateRecord(pkg, uid);
+ if (r.channels.size() == 1
+ && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ return true;
+ }
+ return false;
+ }
+
public int getDeletedChannelCount(String pkg, int uid) {
Preconditions.checkNotNull(pkg);
int deletedCount = 0;
@@ -805,6 +829,35 @@
enabled ? DEFAULT_IMPORTANCE : NotificationManager.IMPORTANCE_NONE);
}
+ @VisibleForTesting
+ void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
+ update.unlockFields(update.getUserLockedFields());
+ update.lockFields(original.getUserLockedFields());
+ if (original.canBypassDnd() != update.canBypassDnd()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
+ }
+ if (original.getLockscreenVisibility() != update.getLockscreenVisibility()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY);
+ }
+ if (original.getImportance() != update.getImportance()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ }
+ if (original.shouldShowLights() != update.shouldShowLights()
+ || original.getLightColor() != update.getLightColor()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
+ }
+ if (!Objects.equals(original.getSound(), update.getSound())) {
+ update.lockFields(NotificationChannel.USER_LOCKED_SOUND);
+ }
+ if (!Arrays.equals(original.getVibrationPattern(), update.getVibrationPattern())
+ || original.shouldVibrate() != update.shouldVibrate()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
+ }
+ if (original.canShowBadge() != update.canShowBadge()) {
+ update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
+ }
+ }
+
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;
@@ -1083,6 +1136,38 @@
channel.getImportance());
}
+ public void updateBadgingEnabled() {
+ if (mBadgingEnabled == null) {
+ mBadgingEnabled = new SparseBooleanArray();
+ }
+ boolean changed = false;
+ // update the cached values
+ for (int index = 0; index < mBadgingEnabled.size(); index++) {
+ int userId = mBadgingEnabled.keyAt(index);
+ final boolean oldValue = mBadgingEnabled.get(userId);
+ final boolean newValue = Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NOTIFICATION_BADGING,
+ DEFAULT_SHOW_BADGE ? 1 : 0, userId) != 0;
+ mBadgingEnabled.put(userId, newValue);
+ changed |= oldValue != newValue;
+ }
+ if (changed) {
+ mRankingHandler.requestSort(false);
+ }
+ }
+
+ public boolean badgingEnabled(UserHandle userHandle) {
+ int userId = userHandle.getIdentifier();
+ if (mBadgingEnabled.indexOfKey(userId) < 0) {
+ mBadgingEnabled.put(userId,
+ Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NOTIFICATION_BADGING,
+ DEFAULT_SHOW_BADGE ? 1 : 0, userId) != 0);
+ }
+ return mBadgingEnabled.get(userId, DEFAULT_SHOW_BADGE);
+ }
+
+
private static class Record {
static int UNKNOWN_UID = UserHandle.USER_NULL;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
index bbd4048..575e0f9 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
@@ -21,6 +21,7 @@
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.util.Locale;
class OtaDexoptShellCommand extends ShellCommand {
final IOtaDexopt mInterface;
@@ -93,7 +94,10 @@
private int runOtaProgress() throws RemoteException {
final float progress = mInterface.getProgress();
final PrintWriter pw = getOutPrintWriter();
- pw.format("%.2f", progress);
+ // Note: The float output is parsed by update_engine. It does needs to be non-localized,
+ // as it's always expected to be "0.xy," never "0,xy" or similar. So use the ROOT
+ // Locale for formatting. (b/37760573)
+ pw.format(Locale.ROOT, "%.2f", progress);
return 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8c1d9fb3..cab6f36 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3616,7 +3616,7 @@
if (matchFactoryOnly) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -3631,14 +3631,14 @@
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
- Binder.getCallingUid(), userId)) {
+ Binder.getCallingUid(), userId, flags)) {
return null;
}
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -3647,13 +3647,17 @@
return null;
}
-
- private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId) {
- // System/shell/root get to see all static libs
- final int appId = UserHandle.getAppId(uid);
- if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
- || appId == Process.ROOT_UID) {
- return false;
+ private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
+ int flags) {
+ // Callers can access only the libs they depend on, otherwise they need to explicitly
+ // ask for the shared libraries given the caller is allowed to access all static libs.
+ if ((flags & PackageManager.MATCH_STATIC_SHARED_LIBRARIES) != 0) {
+ // System/shell/root get to see all static libs
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
+ || appId == Process.ROOT_UID) {
+ return false;
+ }
}
// No package means no static lib as it is always on internal storage
@@ -3848,7 +3852,7 @@
if (!sUserManager.exists(userId)) return null;
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
- if (filterSharedLibPackageLPr(ps, uid, userId)) {
+ if (filterSharedLibPackageLPr(ps, uid, userId, flags)) {
return null;
}
if (ps.pkg == null) {
@@ -3889,7 +3893,7 @@
if (p != null) {
PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) return null;
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
return null;
}
// Note: isEnabledLP() does not apply here - always return info
@@ -4350,7 +4354,6 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- // TODO: We will change version code to long, so in the new API it is long
PackageInfo packageInfo = getPackageInfoVersioned(
libInfo.getDeclaringPackage(), flags, userId);
if (packageInfo == null) {
@@ -4493,7 +4496,8 @@
}
PackageSetting ps = mSettings.getPackageLPr(libEntry.apk);
if (ps != null && !filterSharedLibPackageLPr(ps, Binder.getCallingUid(),
- UserHandle.getUserId(Binder.getCallingUid()))) {
+ UserHandle.getUserId(Binder.getCallingUid()),
+ PackageManager.MATCH_STATIC_SHARED_LIBRARIES)) {
if (libs == null) {
libs = new ArraySet<>();
}
@@ -7548,7 +7552,7 @@
if (listUninstalled) {
list = new ArrayList<>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
continue;
}
final PackageInfo pi = generatePackageInfo(ps, flags, userId);
@@ -7560,7 +7564,7 @@
list = new ArrayList<>(mPackages.size());
for (PackageParser.Package p : mPackages.values()) {
if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
- Binder.getCallingUid(), userId)) {
+ Binder.getCallingUid(), userId, flags)) {
continue;
}
final PackageInfo pi = generatePackageInfo((PackageSetting)
@@ -7665,7 +7669,7 @@
effectiveFlags |= PackageManager.MATCH_ANY_USER;
}
if (ps.pkg != null) {
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
continue;
}
ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
@@ -7689,7 +7693,7 @@
for (PackageParser.Package p : mPackages.values()) {
if (p.mExtras != null) {
PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+ if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
continue;
}
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index c1d68b8..3e920d4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -48,6 +48,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.SystemProperties;
@@ -1686,7 +1687,7 @@
private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
- public void send(int code, Intent intent, String resolvedType,
+ public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
try {
mResult.offer(intent, 5, TimeUnit.SECONDS);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 857025d..6f5c070c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5325,7 +5325,7 @@
@Override
public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
WindowState attached, WindowState imeTarget) {
- final boolean visible = !win.isGoneForLayoutLw() && win.getAttrs().alpha > 0f;
+ final boolean visible = win.isVisibleLw() && win.getAttrs().alpha > 0f;
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisible=" + visible);
applyKeyguardPolicyLw(win, imeTarget);
final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -5960,15 +5960,23 @@
result &= ~ACTION_PASS_TO_USER;
break;
}
- if (telecomManager.isInCall()
- && (result & ACTION_PASS_TO_USER) == 0) {
- // If we are in call but we decided not to pass the key to
- // the application, just pass it to the session service.
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
- break;
- }
}
+ int audioMode = AudioManager.MODE_NORMAL;
+ try {
+ audioMode = getAudioService().getMode();
+ } catch (Exception e) {
+ Log.e(TAG, "Error getting AudioService in interceptKeyBeforeQueueing.", e);
+ }
+ boolean isInCall = (telecomManager != null && telecomManager.isInCall()) ||
+ audioMode == AudioManager.MODE_IN_COMMUNICATION;
+ if (isInCall && (result & ACTION_PASS_TO_USER) == 0) {
+ // If we are in call but we decided not to pass the key to
+ // the application, just pass it to the session service.
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+ break;
+ }
+
}
if (mUseTvRouting || mHandleVolumeKeysInWM) {
// Defer special key handlings to
@@ -6313,7 +6321,7 @@
try {
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
- } catch (RemoteException e) {
+ } catch (Exception e) {
Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
}
break;
@@ -6321,7 +6329,7 @@
try {
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
- } catch (RemoteException e) {
+ } catch (Exception e) {
Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
}
break;
@@ -6332,7 +6340,7 @@
AudioManager.ADJUST_TOGGLE_MUTE,
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
}
- } catch (RemoteException e) {
+ } catch (Exception e) {
Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
}
break;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 423bc0c..a8d19e94 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4607,6 +4607,9 @@
} catch (IOException e) {
Slog.e(TAG, "Failed to read last_reboot_reason file", e);
}
+ if (line == null) {
+ return PowerManager.SHUTDOWN_REASON_UNKNOWN;
+ }
switch (line) {
case REASON_SHUTDOWN:
return PowerManager.SHUTDOWN_REASON_SHUTDOWN;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 70782dd..71c92b8 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -62,6 +62,7 @@
import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Process;
@@ -817,13 +818,35 @@
@Override
public void onServiceDisconnected(ComponentName name) {
synchronized (mLock) {
+ Slog.w(TAG, "Wallpaper service gone: " + name);
+ if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
+ Slog.e(TAG, "Does not match expected wallpaper component "
+ + mWallpaper.wallpaperComponent);
+ }
mService = null;
mEngine = null;
if (mWallpaper.connection == this) {
- // The wallpaper disappeared. If this isn't a system-default one, track
- // crashes and fall back to default if it continues to misbehave.
+ // There is an inherent ordering race between this callback and the
+ // package monitor that receives notice that a package is being updated,
+ // so we cannot quite trust at this moment that we know for sure that
+ // this is not an update. If we think this is a genuine non-update
+ // wallpaper outage, we do our "wait for reset" work as a continuation,
+ // a short time in the future, specifically to allow any pending package
+ // update message on this same looper thread to be processed.
+ if (!mWallpaper.wallpaperUpdating) {
+ mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
+ 1000);
+ }
+ }
+ }
+ }
+
+ private void processDisconnect(final ServiceConnection connection) {
+ synchronized (mLock) {
+ // The wallpaper disappeared. If this isn't a system-default one, track
+ // crashes and fall back to default if it continues to misbehave.
+ if (connection == mWallpaper.connection) {
final ComponentName wpService = mWallpaper.wallpaperComponent;
- Slog.w(TAG, "Wallpaper service gone: " + wpService);
if (!mWallpaper.wallpaperUpdating
&& mWallpaper.userId == mCurrentUserId
&& !Objects.equals(mDefaultWallpaperComponent, wpService)
@@ -836,7 +859,7 @@
// during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
if (mWallpaper.lastDiedTime != 0
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
- > SystemClock.uptimeMillis()) {
+ > SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
} else {
@@ -844,18 +867,22 @@
// If we didn't reset it right away, do so after we couldn't connect to
// it for an extended amount of time to avoid having a black wallpaper.
- FgThread.getHandler().removeCallbacks(mResetRunnable);
- FgThread.getHandler().postDelayed(mResetRunnable,
- WALLPAPER_RECONNECT_TIMEOUT_MS);
+ final Handler fgHandler = FgThread.getHandler();
+ fgHandler.removeCallbacks(mResetRunnable);
+ fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
if (DEBUG_LIVE) {
Slog.i(TAG, "Started wallpaper reconnect timeout for " + wpService);
}
}
- final String flattened = name.flattenToString();
+ final String flattened = wpService.flattenToString();
EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
flattened.substring(0, Math.min(flattened.length(),
MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
}
+ } else {
+ if (DEBUG_LIVE) {
+ Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 982561c..96ea5e5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1248,11 +1248,11 @@
*/
@Override
int getOrientation(int candidate) {
- // We do not allow non-fullscreen apps to influence orientation at and beyond O. While we do
+ // We do not allow non-fullscreen apps to influence orientation beyond O. While we do
// throw an exception in {@link Activity#onCreate} and
// {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
// other calculations aren't affected.
- if (!fillsParent() && mTargetSdk >= O) {
+ if (!fillsParent() && mTargetSdk > O) {
// Can't specify orientation if app doesn't fill parent.
return SCREEN_ORIENTATION_UNSET;
}
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index b927e67..9c44c14 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import android.app.ActivityManager.StackId;
import android.app.RemoteAction;
@@ -285,13 +286,16 @@
if (StackId.tasksAreFloating(mStackId)) {
// Floating tasks should not be resized to the screen's bounds.
- if (bounds.width() == mTmpDisplayBounds.width() &&
+ if (mStackId == PINNED_STACK_ID && bounds.width() == mTmpDisplayBounds.width() &&
bounds.height() == mTmpDisplayBounds.height()) {
// If the bounds we are animating is the same as the fullscreen stack
// dimensions, then apply the same inset calculations that we normally do for
// the fullscreen stack, without intersecting it with the display bounds
stableBounds.inset(mTmpStableInsets);
nonDecorBounds.inset(mTmpNonDecorInsets);
+ // Move app bounds to zero to apply intersection with parent correctly. They are
+ // used only for evaluating width and height, so it's OK to move them around.
+ config.appBounds.offsetTo(0, 0);
intersectParentBounds = true;
}
width = (int) (stableBounds.width() / density);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index b79173c..1bbe1d0 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -275,6 +275,15 @@
mPersister.removeObsoleteFiles(persistentTaskIds, runningUserIds);
}
+ /**
+ * Temporarily pauses/unpauses persisting of task snapshots.
+ *
+ * @param paused Whether task snapshot persisting should be paused.
+ */
+ void setPersisterPaused(boolean paused) {
+ mPersister.setPaused(paused);
+ }
+
void dump(PrintWriter pw, String prefix) {
mCache.dump(pw, prefix);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index e5c7a72..0287070 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -60,6 +60,8 @@
private final ArrayDeque<WriteQueueItem> mWriteQueue = new ArrayDeque<>();
@GuardedBy("mLock")
private boolean mQueueIdling;
+ @GuardedBy("mLock")
+ private boolean mPaused;
private boolean mStarted;
private final Object mLock = new Object();
private final DirectoryResolver mDirectoryResolver;
@@ -127,6 +129,15 @@
}
}
+ void setPaused(boolean paused) {
+ synchronized (mLock) {
+ mPaused = paused;
+ if (!paused) {
+ mLock.notifyAll();
+ }
+ }
+ }
+
@TestApi
void waitForQueueEmpty() {
while (true) {
@@ -142,7 +153,9 @@
@GuardedBy("mLock")
private void sendToQueueLocked(WriteQueueItem item) {
mWriteQueue.offer(item);
- mLock.notifyAll();
+ if (!mPaused) {
+ mLock.notifyAll();
+ }
}
private File getDirectory(int userId) {
@@ -185,7 +198,11 @@
while (true) {
WriteQueueItem next;
synchronized (mLock) {
- next = mWriteQueue.poll();
+ if (mPaused) {
+ next = null;
+ } else {
+ next = mWriteQueue.poll();
+ }
}
if (next != null) {
next.write();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 067cc09..dd790a9 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -255,12 +255,19 @@
mWindowPlacerLocked.requestTraversal();
}
- if (mAnimating && !wasAnimating && Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
- Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+ if (mAnimating && !wasAnimating) {
+
+ // Usually app transitions but quite a load onto the system already (with all the things
+ // happening in app), so pause task snapshot persisting to not increase the load.
+ mService.mTaskSnapshotController.setPersisterPaused(true);
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+ }
}
if (!mAnimating && wasAnimating) {
mWindowPlacerLocked.requestTraversal();
+ mService.mTaskSnapshotController.setPersisterPaused(false);
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index ddd1ca5..e576f2f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -41,6 +41,7 @@
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.Debug;
import android.os.Trace;
import android.util.ArraySet;
@@ -683,9 +684,11 @@
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
// Create a new surface for the thumbnail
+ WindowState window = appToken.findMainWindow();
SurfaceControl surfaceControl = new SurfaceControl(mService.mFxSession,
"thumbnail anim", dirty.width(), dirty.height(),
- PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+ PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN,
+ appToken.windowType, window.mOwnerUid);
surfaceControl.setLayerStack(display.getLayerStack());
if (SHOW_TRANSACTIONS) {
Slog.i(TAG, " THUMBNAIL " + surfaceControl + ": CREATE");
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 0cf4994..262516d 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -18,20 +18,19 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+
import android.app.ActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
import android.app.NotificationManager;
-import android.content.Context;
import android.os.UserHandle;
+import android.provider.Settings.Secure;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -43,7 +42,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BadgeExtractorTest {
+public class BadgeExtractorTest extends NotificationTestCase {
@Mock RankingConfig mConfig;
@@ -59,7 +58,11 @@
MockitoAnnotations.initMocks(this);
}
- private NotificationRecord getNotificationRecord(NotificationChannel channel) {
+ private NotificationRecord getNotificationRecord(boolean showBadge, int importanceHigh) {
+ NotificationChannel channel = new NotificationChannel("a", "a", importanceHigh);
+ channel.setShowBadge(showBadge);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
final Builder builder = new Builder(getContext())
.setContentTitle("foo")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -73,10 +76,6 @@
return r;
}
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
//
// Tests
//
@@ -86,13 +85,9 @@
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
- NotificationChannel channel =
- new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
- when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
- channel.setShowBadge(false);
-
- NotificationRecord r = getNotificationRecord(channel);
+ NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
extractor.process(r);
@@ -104,13 +99,9 @@
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(false);
- NotificationChannel channel =
- new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
- channel.setShowBadge(true);
- when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
-
- NotificationRecord r = getNotificationRecord(channel);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
extractor.process(r);
@@ -122,13 +113,9 @@
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
- NotificationChannel channel =
- new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
- channel.setShowBadge(true);
- when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
-
- NotificationRecord r = getNotificationRecord(channel);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
extractor.process(r);
@@ -140,13 +127,23 @@
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(false);
- NotificationChannel channel =
- new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
- channel.setShowBadge(false);
- when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+ NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
- NotificationRecord r = getNotificationRecord(channel);
+ extractor.process(r);
+
+ assertFalse(r.canShowBadge());
+ }
+
+ @Test
+ public void testAppYesChannelYesUserNo() throws Exception {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(false);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
extractor.process(r);
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index d4904f5..39caa3c 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -34,7 +34,6 @@
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
-import android.content.Context;
import android.app.NotificationChannel;
import android.graphics.Color;
import android.media.AudioAttributes;
@@ -47,7 +46,6 @@
import android.os.VibrationEffect;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -69,7 +67,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class BuzzBeepBlinkTest {
+public class BuzzBeepBlinkTest extends NotificationTestCase {
@Mock AudioManager mAudioManager;
@Mock Vibrator mVibrator;
@@ -328,10 +326,6 @@
eq(CUSTOM_LIGHT_COLOR), anyInt(), eq(CUSTOM_LIGHT_ON), eq(CUSTOM_LIGHT_OFF));
}
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
//
// Tests
//
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 24cb72e..f92bd84 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -25,7 +25,6 @@
import android.app.NotificationManager;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -38,7 +37,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class GlobalSortKeyComparatorTest {
+public class GlobalSortKeyComparatorTest extends NotificationTestCase {
private final String PKG = "PKG";
private final int UID = 1111111;
@@ -46,24 +45,23 @@
@Test
public void testComparator() throws Exception {
- Notification n = new Notification.Builder(
- InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.build();
- NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord left = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
"", 1499), getDefaultChannel());
left.setGlobalSortKey("first");
- NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord right = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
"", 1499), getDefaultChannel());
right.setGlobalSortKey("second");
- NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord last = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
@@ -86,16 +84,15 @@
@Test
public void testNoCrash_leftNull() throws Exception {
- Notification n = new Notification.Builder(
- InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.build();
- NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord left = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
"", 1499), getDefaultChannel());
- NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord right = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
@@ -117,17 +114,16 @@
@Test
public void testNoCrash_rightNull() throws Exception {
- Notification n = new Notification.Builder(
- InstrumentationRegistry.getContext(), TEST_CHANNEL_ID)
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.build();
- NotificationRecord left = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord left = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
"", 1499), getDefaultChannel());
left.setGlobalSortKey("not null");
- NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
+ NotificationRecord right = new NotificationRecord(getContext(),
new StatusBarNotification(PKG,
PKG, 1, "media", UID, UID, n,
new UserHandle(UserHandle.myUserId()),
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 05c33a4..8dd1779 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -34,10 +34,8 @@
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.Context;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -46,15 +44,11 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class GroupHelperTest {
+public class GroupHelperTest extends NotificationTestCase {
private @Mock GroupHelper.Callback mCallback;
private GroupHelper mGroupHelper;
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 3dbd803..d325e10 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -24,10 +24,8 @@
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.app.NotificationChannel;
-import android.content.Context;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -43,7 +41,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ImportanceExtractorTest {
+public class ImportanceExtractorTest extends NotificationTestCase {
@Mock RankingConfig mConfig;
@@ -75,10 +73,6 @@
return r;
}
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
//
// Tests
//
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index dde08fc..1e5f96f 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -35,7 +35,6 @@
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -51,7 +50,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationComparatorTest {
+public class NotificationComparatorTest extends NotificationTestCase {
@Mock Context mContext;
@Mock TelecomManager mTm;
@Mock RankingHandler handler;
@@ -83,10 +82,8 @@
MockitoAnnotations.initMocks(this);
int userId = UserHandle.myUserId();
- when(mContext.getResources()).thenReturn(
- InstrumentationRegistry.getTargetContext().getResources());
- when(mContext.getContentResolver()).thenReturn(
- InstrumentationRegistry.getTargetContext().getContentResolver());
+ when(mContext.getResources()).thenReturn(getContext().getResources());
+ when(mContext.getContentResolver()).thenReturn(getContext().getContentResolver());
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getSystemService(eq(Context.TELECOM_SERVICE))).thenReturn(mTm);
when(mTm.getDefaultDialerPackage()).thenReturn(callPkg);
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
index f0f4c4d..725e8f2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -38,7 +38,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationListenerServiceTest {
+public class NotificationListenerServiceTest extends NotificationTestCase {
private String[] mKeys = new String[] { "key", "key1", "key2", "key3"};
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 177c02d..9afb2d2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -52,9 +52,9 @@
import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
+import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -75,7 +75,7 @@
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
-public class NotificationManagerServiceTest {
+public class NotificationManagerServiceTest extends NotificationTestCase {
private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private final int uid = Binder.getCallingUid();
@@ -86,7 +86,7 @@
private IPackageManager mPackageManager;
@Mock
private PackageManager mPackageManagerClient;
- private Context mContext = InstrumentationRegistry.getTargetContext();
+ private Context mContext = getContext();
private final String PKG = mContext.getPackageName();
private TestableLooper mTestableLooper;
@Mock
@@ -122,6 +122,12 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
+ // most tests assume badging is enabled
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 1,
+ UserHandle.getUserHandleForUid(uid).getIdentifier());
+
mNotificationManagerService = new TestableNotificationManagerService(mContext);
// MockPackageManager - default returns ApplicationInfo with matching calling UID
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 1c8ca84..267d2a6d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -40,7 +40,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -56,7 +55,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class NotificationRecordTest {
+public class NotificationRecordTest extends NotificationTestCase {
private final Context mMockContext = Mockito.mock(Context.class);
@Mock PackageManager mPm;
@@ -96,8 +95,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mMockContext.getResources()).thenReturn(
- InstrumentationRegistry.getContext().getResources());
+ when(mMockContext.getResources()).thenReturn(getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java b/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
new file mode 100644
index 0000000..cc30aab
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationTestCase.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.testing.TestableContext;
+
+import org.junit.Rule;
+
+
+public class NotificationTestCase {
+ @Rule
+ public final TestableContext mContext =
+ new TestableContext(InstrumentationRegistry.getContext(), null);
+
+ protected Context getContext() {
+ return mContext;
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 7bef033..0f8c815 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -49,12 +49,16 @@
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
+import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.TestableContext;
+import android.testing.TestableSettingsProvider;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.Xml;
import java.io.BufferedInputStream;
@@ -80,16 +84,19 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class RankingHelperTest {
+public class RankingHelperTest extends NotificationTestCase {
private static final String PKG = "com.android.server.notification";
private static final int UID = 0;
+ private static final UserHandle USER = UserHandle.getUserHandleForUid(UID);
private static final String UPDATED_PKG = "updatedPkg";
private static final int UID2 = 1111111;
+ private static final UserHandle USER2 = UserHandle.getUserHandleForUid(UID2);
private static final String TEST_CHANNEL_ID = "test_channel_id";
@Mock NotificationUsageStats mUsageStats;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
+ @Mock Context mContext;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
@@ -104,69 +111,11 @@
private RankingHelper mHelper;
private AudioAttributes mAudioAttributes;
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
UserHandle user = UserHandle.ALL;
- mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
- new String[] {ImportanceExtractor.class.getName()});
-
- mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
- .setContentTitle("A")
- .setGroup("G")
- .setSortKey("A")
- .setWhen(1205)
- .build();
- mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel());
-
- mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
- .setContentTitle("B")
- .setGroup("G")
- .setSortKey("B")
- .setWhen(1200)
- .build();
- mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
- null, System.currentTimeMillis()), getDefaultChannel());
-
- mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
- .setContentTitle("C")
- .setWhen(1201)
- .build();
- mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
- null, System.currentTimeMillis()), getDefaultChannel());
-
- mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
- .setContentTitle("D")
- .setWhen(1202)
- .build();
- mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
- null, System.currentTimeMillis()), getDefaultChannel());
-
- mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
- .setContentTitle("E")
- .setWhen(1201)
- .setSortKey("A")
- .build();
- mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
- "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
- null, System.currentTimeMillis()), getDefaultChannel());
-
- mAudioAttributes = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
- .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
- .build();
-
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
final ApplicationInfo upgrade = new ApplicationInfo();
@@ -174,6 +123,67 @@
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
+ when(mContext.getResources()).thenReturn(
+ InstrumentationRegistry.getContext().getResources());
+ when(mContext.getPackageManager()).thenReturn(mPm);
+ when(mContext.getApplicationInfo()).thenReturn(legacy);
+ // most tests assume badging is enabled
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
+
+ mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
+ new String[] {ImportanceExtractor.class.getName()});
+
+ mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("A")
+ .setGroup("G")
+ .setSortKey("A")
+ .setWhen(1205)
+ .build();
+ mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
+ PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
+ null, System.currentTimeMillis()), getDefaultChannel());
+
+ mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("B")
+ .setGroup("G")
+ .setSortKey("B")
+ .setWhen(1200)
+ .build();
+ mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
+ PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
+ null, System.currentTimeMillis()), getDefaultChannel());
+
+ mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("C")
+ .setWhen(1201)
+ .build();
+ mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
+ PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
+ null, System.currentTimeMillis()), getDefaultChannel());
+
+ mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("D")
+ .setWhen(1202)
+ .build();
+ mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
+ PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
+ null, System.currentTimeMillis()), getDefaultChannel());
+
+ mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentTitle("E")
+ .setWhen(1201)
+ .setSortKey("A")
+ .build();
+ mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
+ PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
+ null, System.currentTimeMillis()), getDefaultChannel());
+
+ mAudioAttributes = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+ .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
+ .build();
}
private NotificationChannel getDefaultChannel() {
@@ -229,6 +239,10 @@
assertEquals(expected.getName(), actual.getName());
}
+ private NotificationChannel getChannel() {
+ return new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ }
+
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -644,14 +658,119 @@
}
@Test
+ public void testClearLockedFields() throws Exception {
+ final NotificationChannel channel = getChannel();
+ mHelper.clearLockedFields(channel);
+ assertEquals(0, channel.getUserLockedFields());
+
+ channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_IMPORTANCE);
+ mHelper.clearLockedFields(channel);
+ assertEquals(0, channel.getUserLockedFields());
+ }
+
+ @Test
+ public void testLockFields_soundAndVibration() throws Exception {
+ mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+ final NotificationChannel update1 = getChannel();
+ update1.setSound(new Uri.Builder().scheme("test").build(),
+ new AudioAttributes.Builder().build());
+ update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
+ mHelper.updateNotificationChannel(PKG, UID, update1);
+ assertEquals(NotificationChannel.USER_LOCKED_SOUND,
+ mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+ .getUserLockedFields());
+
+ NotificationChannel update2 = getChannel();
+ update2.enableVibration(true);
+ mHelper.updateNotificationChannel(PKG, UID, update2);
+ assertEquals(NotificationChannel.USER_LOCKED_SOUND
+ | NotificationChannel.USER_LOCKED_VIBRATION,
+ mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+ .getUserLockedFields());
+ }
+
+ @Test
+ public void testLockFields_vibrationAndLights() throws Exception {
+ mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+ final NotificationChannel update1 = getChannel();
+ update1.setVibrationPattern(new long[]{7945, 46 ,246});
+ mHelper.updateNotificationChannel(PKG, UID, update1);
+ assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
+ mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+ .getUserLockedFields());
+
+ final NotificationChannel update2 = getChannel();
+ update2.enableLights(true);
+ mHelper.updateNotificationChannel(PKG, UID, update2);
+ assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
+ | NotificationChannel.USER_LOCKED_LIGHTS,
+ mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+ .getUserLockedFields());
+ }
+
+ @Test
+ public void testLockFields_lightsAndImportance() throws Exception {
+ mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+
+ final NotificationChannel update1 = getChannel();
+ update1.setLightColor(Color.GREEN);
+ mHelper.updateNotificationChannel(PKG, UID, update1);
+ assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
+ mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+ .getUserLockedFields());
+
+ final NotificationChannel update2 = getChannel();
+ update2.setImportance(IMPORTANCE_DEFAULT);
+ mHelper.updateNotificationChannel(PKG, UID, update2);
+ assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
+ | NotificationChannel.USER_LOCKED_IMPORTANCE,
+ mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+ .getUserLockedFields());
+ }
+
+ @Test
+ public void testLockFields_visibilityAndDndAndBadge() throws Exception {
+ mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+ assertEquals(0,
+ mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
+ .getUserLockedFields());
+
+ final NotificationChannel update1 = getChannel();
+ update1.setBypassDnd(true);
+ mHelper.updateNotificationChannel(PKG, UID, update1);
+ assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
+ mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
+ .getUserLockedFields());
+
+ final NotificationChannel update2 = getChannel();
+ update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ mHelper.updateNotificationChannel(PKG, UID, update2);
+ assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_VISIBILITY,
+ mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
+ .getUserLockedFields());
+
+ final NotificationChannel update3 = getChannel();
+ update3.setShowBadge(false);
+ mHelper.updateNotificationChannel(PKG, UID, update3);
+ assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
+ | NotificationChannel.USER_LOCKED_VISIBILITY
+ | NotificationChannel.USER_LOCKED_SHOW_BADGE,
+ mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
+ .getUserLockedFields());
+ }
+
+ @Test
public void testDeleteNonExistentChannel() throws Exception {
mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
}
@Test
public void testGetDeletedChannel() throws Exception {
- NotificationChannel channel =
- new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ NotificationChannel channel = getChannel();
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
@@ -754,6 +873,15 @@
}
@Test
+ public void testOnlyHasDefaultChannel() throws Exception {
+ assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID));
+ assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2));
+
+ mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+ assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID));
+ }
+
+ @Test
public void testCreateChannel_defaultChannelId() throws Exception {
try {
mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
@@ -1084,4 +1212,36 @@
object.getInt("channelCount"));
}
}
+
+ @Test
+ public void testBadgingOverrideTrue() throws Exception {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 1,
+ USER.getIdentifier());
+ mHelper.updateBadgingEnabled(); // would be called by settings observer
+ assertTrue(mHelper.badgingEnabled(USER));
+ }
+
+ @Test
+ public void testBadgingOverrideFalse() throws Exception {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 0,
+ USER.getIdentifier());
+ mHelper.updateBadgingEnabled(); // would be called by settings observer
+ assertFalse(mHelper.badgingEnabled(USER));
+ }
+
+ @Test
+ public void testBadgingOverrideUserIsolation() throws Exception {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 0,
+ USER.getIdentifier());
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NOTIFICATION_BADGING, 1,
+ USER2.getIdentifier());
+ mHelper.updateBadgingEnabled(); // would be called by settings observer
+ assertFalse(mHelper.badgingEnabled(USER));
+ assertTrue(mHelper.badgingEnabled(USER2));
+ }
+
}
diff --git a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
index 07f3162..e354267 100644
--- a/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RateEstimatorTest.java
@@ -26,7 +26,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class RateEstimatorTest {
+public class RateEstimatorTest extends NotificationTestCase {
private long mTestStartTime;
private RateEstimator mEstimator;
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index bc25860..07b21fb 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -27,11 +27,9 @@
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.content.Context;
import android.os.SystemClock;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Slog;
@@ -51,7 +49,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class SnoozeHelperTest {
+public class SnoozeHelperTest extends NotificationTestCase {
private static final String TEST_CHANNEL_ID = "test_channel_id";
@Mock SnoozeHelper.Callback mCallback;
@@ -60,10 +58,6 @@
private SnoozeHelper mSnoozeHelper;
- private Context getContext() {
- return InstrumentationRegistry.getTargetContext();
- }
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
diff --git a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index d09b858..4ac0c65 100644
--- a/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -32,7 +32,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ValidateNotificationPeopleTest {
+public class ValidateNotificationPeopleTest extends NotificationTestCase {
@Test
public void testNoExtra() throws Exception {
diff --git a/services/tests/servicestests/res/raw/backup_file_with_long_name b/services/tests/servicestests/res/raw/backup_file_with_long_name
new file mode 100644
index 0000000..265a0ba
--- /dev/null
+++ b/services/tests/servicestests/res/raw/backup_file_with_long_name
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 8784dd5..6b25d12 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -47,6 +47,7 @@
import com.android.frameworks.servicestests.R;
import com.android.server.backup.FileMetadata;
+import com.android.server.backup.RefactoredBackupManagerService;
import com.android.server.backup.restore.PerformAdbRestoreTask;
import com.android.server.backup.restore.RestorePolicy;
import com.android.server.backup.testutils.PackageManagerStub;
@@ -61,6 +62,7 @@
import org.mockito.MockitoAnnotations;
import java.io.InputStream;
+import java.util.Arrays;
import java.util.List;
@SmallTest
@@ -71,6 +73,7 @@
private static final String TELEPHONY_PACKAGE_SIGNATURE_SHA256 =
"301aa3cb081134501c45f1422abc66c24224fd5ded5fdc8f17e697176fd866aa";
private static final int TELEPHONY_PACKAGE_VERSION = 25;
+ private static final String TEST_PACKAGE_NAME = "com.android.backup.testing";
private static final Signature FAKE_SIGNATURE_1 = new Signature("1234");
private static final Signature FAKE_SIGNATURE_2 = new Signature("5678");
@@ -122,6 +125,45 @@
}
@Test
+ public void readTarHeaders_backupNotEncrypted_correctlyReadsPaxHeader() throws Exception {
+ // Files with long names (>100 chars) will force backup to add PAX header.
+ InputStream inputStream = mContext.getResources().openRawResource(
+ R.raw.backup_file_with_long_name);
+ InputStream tarInputStream = PerformAdbRestoreTask.parseBackupFileHeaderAndReturnTarStream(
+ inputStream, null);
+ TarBackupReader tarBackupReader = new TarBackupReader(tarInputStream,
+ mBytesReadListenerMock, mBackupManagerMonitorMock);
+
+ // Read manifest file.
+ FileMetadata fileMetadata = tarBackupReader.readTarHeaders();
+ Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
+ fileMetadata);
+ RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+
+ assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
+ assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
+ assertThat(fileMetadata.path).isEqualTo(
+ RefactoredBackupManagerService.BACKUP_MANIFEST_FILENAME);
+
+ tarBackupReader.skipTarPadding(fileMetadata.size);
+
+ // Read actual file (PAX header will only exist here).
+ fileMetadata = tarBackupReader.readTarHeaders();
+ signatures = tarBackupReader.readAppManifestAndReturnSignatures(
+ fileMetadata);
+ restorePolicy = tarBackupReader.chooseRestorePolicy(
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+
+ assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
+ assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
+ char[] expectedFileNameChars = new char[200];
+ Arrays.fill(expectedFileNameChars, '1');
+ String expectedFileName = new String(expectedFileNameChars);
+ assertThat(fileMetadata.path).isEqualTo(expectedFileName);
+ }
+
+ @Test
public void readAppManifest_backupEncrypted_correctlyParsesAppManifest() throws Exception {
InputStream inputStream = mContext.getResources().openRawResource(
R.raw.backup_telephony_with_password);
@@ -331,7 +373,8 @@
}
@Test
- public void chooseRestorePolicy_systemAppWithBackupAgentAndRestoreAnyVersion_returnsAccept() throws Exception {
+ public void chooseRestorePolicy_systemAppWithBackupAgentAndRestoreAnyVersion_returnsAccept()
+ throws Exception {
InputStream inputStream = mContext.getResources().openRawResource(
R.raw.backup_telephony_no_password);
InputStream tarInputStream = PerformAdbRestoreTask.parseBackupFileHeaderAndReturnTarStream(
@@ -486,5 +529,5 @@
assertThat(bundleCaptor.getValue().get(EXTRA_LOG_EVENT_ID)).isEqualTo(
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER);
}
+}
-}
\ No newline at end of file
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
index 4cc0cef..55bfccf 100644
--- a/services/usb/Android.mk
+++ b/services/usb/Android.mk
@@ -7,9 +7,10 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
-LOCAL_JAVA_LIBRARIES := services.core
-LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb-V1.0-java-static \
-android.hardware.usb-V1.1-java-static \
-android.hidl.manager-V1.0-java-static
+LOCAL_JAVA_LIBRARIES := services.core \
+android.hidl.manager-V1.0-java
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb-V1.0-java \
+android.hardware.usb-V1.1-java
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index fc406ee..58262e1 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -22,7 +22,6 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.mbms.IMbmsStreamingManagerCallback;
@@ -96,15 +95,15 @@
/**
* Create a new MbmsStreamingManager using the given subscription ID.
*
- * Note that this call will bind a remote service and that may take a bit. This
- * may throw an {@link MbmsException}, indicating errors that may happen during
- * the initialization or binding process.
+ * Note that this call will bind a remote service. You may not call this method on your app's
+ * main thread. This may throw an {@link MbmsException}, indicating errors that may happen
+ * during the initialization or binding process.
*
- * @param context
- * @param listener
- * @param streamingAppName
- * @param subscriptionId
- * @return
+ * @param context The {@link Context} to use.
+ * @param listener A callback object on which you wish to receive results of asynchronous
+ * operations.
+ * @param streamingAppName The name of the streaming app, as specified by the carrier.
+ * @param subscriptionId The subscription ID to use.
*/
public static MbmsStreamingManager create(Context context,
IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
@@ -117,9 +116,7 @@
/**
* Create a new MbmsStreamingManager using the system default data subscription ID.
- *
- * Note that this call will bind a remote service and that may take a bit. This
- * may throw an IllegalArgumentException or RemoteException.
+ * See {@link #create(Context, IMbmsStreamingManagerCallback, String, int)}.
*/
public static MbmsStreamingManager create(Context context,
IMbmsStreamingManagerCallback listener, String streamingAppName)
@@ -156,19 +153,29 @@
*
* Multiple calls replace the list of serviceClasses of interest.
*
- * May throw an IllegalArgumentException or RemoteException.
+ * This may throw an {@link MbmsException} containing one of the following errors:
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+ * {@link MbmsException#ERROR_NOT_YET_INITIALIZED}
+ * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
*
- * Synchronous responses include
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
- *
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
- * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
- * <li>ERROR_MSDC_END_OF_SESSION</li>
+ * Asynchronous error codes via the {@link IMbmsStreamingManagerCallback#error(int, String)}
+ * callback can include any of the errors except:
+ * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
+ * {@link MbmsException#ERROR_INVALID_SERVICE_ID}
+ * {@link MbmsException#ERROR_END_OF_SESSION}
*/
- public int getStreamingServices(List<String> classList) {
- return 0;
+ public void getStreamingServices(List<String> classList) throws MbmsException {
+ if (mService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+ try {
+ int returnCode = mService.getStreamingServices(mAppName, mSubscriptionId, classList);
+ if (returnCode != MbmsException.SUCCESS) {
+ throw new MbmsException(returnCode);
+ }
+ } catch (RemoteException e) {
+ throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
+ }
}
/**
@@ -262,7 +269,7 @@
} catch (RemoteException e) {
mService = null;
Log.e(LOG_TAG, "Service died before initialization");
- throw new MbmsException(MbmsException.ERROR_INITIALIZATION_REMOTE_EXCEPTION);
+ throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
}
}
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index d6e74cf..dcdda86 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -463,9 +463,28 @@
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message, boolean statusReportRequested) {
- SubmitPduBase spb;
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested,
+ SubscriptionManager.getDefaultSmsSubscriptionId());
+ }
- if (useCdmaFormatForMoSms()) {
+ /**
+ * Get an SMS-SUBMIT PDU for a destination address and a message.
+ * This method will not attempt to use any GSM national language 7 bit encodings.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message String representation of the message payload.
+ * @param statusReportRequested Indicates whether a report is requested for this message.
+ * @param subId Subscription of the message
+ * @return a <code>SubmitPdu</code> containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message, boolean statusReportRequested, int subId) {
+ SubmitPduBase spb;
+ if (useCdmaFormatForMoSms(subId)) {
spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
destinationAddress, message, statusReportRequested, null);
} else {
@@ -758,12 +777,27 @@
* @return true if Cdma format should be used for MO SMS, false otherwise.
*/
private static boolean useCdmaFormatForMoSms() {
- if (!SmsManager.getDefault().isImsSmsSupported()) {
+ // IMS is registered with SMS support, check the SMS format supported
+ return useCdmaFormatForMoSms(SubscriptionManager.getDefaultSmsSubscriptionId());
+ }
+
+ /**
+ * Determines whether or not to use CDMA format for MO SMS.
+ * If SMS over IMS is supported, then format is based on IMS SMS format,
+ * otherwise format is based on current phone type.
+ *
+ * @param subId Subscription for which phone type is returned.
+ *
+ * @return true if Cdma format should be used for MO SMS, false otherwise.
+ */
+ private static boolean useCdmaFormatForMoSms(int subId) {
+ SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId);
+ if (!smsManager.isImsSmsSupported()) {
// use Voice technology to determine SMS format.
- return isCdmaVoice();
+ return isCdmaVoice(subId);
}
// IMS is registered with SMS support, check the SMS format supported
- return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
+ return (SmsConstants.FORMAT_3GPP2.equals(smsManager.getImsSmsFormat()));
}
/**
@@ -772,10 +806,18 @@
* @return true if current phone type is cdma, false otherwise.
*/
private static boolean isCdmaVoice() {
- int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
- return (PHONE_TYPE_CDMA == activePhone);
+ return isCdmaVoice(SubscriptionManager.getDefaultSmsSubscriptionId());
}
+ /**
+ * Determines whether or not to current phone type is cdma
+ *
+ * @return true if current phone type is cdma, false otherwise.
+ */
+ private static boolean isCdmaVoice(int subId) {
+ int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId);
+ return (PHONE_TYPE_CDMA == activePhone);
+ }
/**
* Decide if the carrier supports long SMS.
* {@hide}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0dd6c0b..c8ff08c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6611,5 +6611,26 @@
}
return false;
}
+
+ /**
+ * Get the most recently available signal strength information.
+ *
+ * Get the most recent SignalStrength information reported by the modem. Due
+ * to power saving this information may not always be current.
+ * @return the most recent cached signal strength info from the modem
+ * @hide
+ */
+ @Nullable
+ public SignalStrength getSignalStrength() {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getSignalStrength(getSubId());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#getSignalStrength", e);
+ }
+ return null;
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index cc4a02a..e8680ea 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -16,16 +16,21 @@
package android.telephony.mbms;
-import android.os.RemoteException;
-
/** @hide */
-public class MbmsException extends RemoteException {
+public class MbmsException extends Exception {
public static final int SUCCESS = 0;
public static final int ERROR_NO_SERVICE_INSTALLED = 1;
public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2;
public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3;
- public static final int ERROR_INITIALIZATION_REMOTE_EXCEPTION = 4;
+ public static final int ERROR_UNKNOWN_REMOTE_EXCEPTION = 4;
public static final int ERROR_ALREADY_INITIALIZED = 5;
+ public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
+ public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
+ public static final int ERROR_UNABLE_TO_START_SERVICE = 8;
+ public static final int ERROR_INVALID_SERVICE_ID = 9;
+ public static final int ERROR_END_OF_SESSION = 10;
+ public static final int ERROR_NOT_YET_INITIALIZED = 11;
+ public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 12;
private final int mErrorCode;
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index cb621c8..f167f0ab 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -114,6 +114,7 @@
sessionEndTime = (java.util.Date) in.readSerializable();
}
+ @Override
public void writeToParcel(Parcel dest, int flags) {
Set<Locale> keySet = names.keySet();
dest.writeInt(keySet.size());
@@ -128,7 +129,33 @@
dest.writeSerializable(sessionEndTime);
}
+ @Override
public int describeContents() {
return 0;
}
+
+ public Map<Locale, String> getNames() {
+ return names;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ public Date getSessionStartTime() {
+ return sessionStartTime;
+ }
+
+ public Date getSessionEndTime() {
+ return sessionEndTime;
+ }
+
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index ddc661d..fed0a40 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -29,22 +29,8 @@
*/
interface IMbmsStreamingService
{
- /**
- * Initialize streaming service
- * Registers this listener, subId with this appName
- *
- */
int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId);
-
- /**
- * - Registers serviceClasses of interest with the uid/appName/subId key.
- * - Starts asynch fetching data on streaming services of matching classes to be reported
- * later by callback.
- *
- * Note that subsequent calls with the same callback, appName, subId and uid will replace
- * the service class list.
- */
int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
/**
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index 9f0c0e9..e23d12b 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -20,7 +20,7 @@
import android.os.RemoteException;
import android.telephony.mbms.IMbmsStreamingManagerCallback;
import android.telephony.mbms.IStreamingServiceCallback;
-import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.MbmsException;
import java.util.List;
@@ -29,16 +29,42 @@
* TODO: future systemapi
*/
public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
-
+ /**
+ * Initialize streaming service for this app and subId, registering the listener.
+ *
+ * @param listener The callback to use to communicate with the app.
+ * @param appName The app name as negotiated with the wireless carrier.
+ * @param subscriptionId The subscription ID to use.
+ * @return {@link MbmsException#SUCCESS}, {@link MbmsException#ERROR_ALREADY_INITIALIZED}, or
+ * {@link MbmsException#ERROR_APP_PERMISSIONS_NOT_GRANTED}
+ */
@Override
- public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId)
- throws RemoteException {
+ public int initialize(IMbmsStreamingManagerCallback listener, String appName,
+ int subscriptionId) throws RemoteException {
return 0;
}
+ /**
+ * Registers serviceClasses of interest with the appName/subId key.
+ * Starts async fetching data on streaming services of matching classes to be reported
+ * later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)}
+ *
+ * Note that subsequent calls with the same uid, appName and subId will replace
+ * the service class list.
+ *
+ * @param appName The app name as negotiated with the wireless carrier.
+ * @param subscriptionId The subscription id to use.
+ * @param serviceClasses The service classes that the app wishes to get info on. The strings
+ * may contain arbitrary data as negotiated between the app and the
+ * carrier.
+ * @return One of {@link MbmsException#SUCCESS},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND},
+ * {@link MbmsException#ERROR_NOT_YET_INITIALIZED}, or
+ * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ */
@Override
- public int getStreamingServices(String appName, int subId, List<String> serviceClasses)
- throws RemoteException {
+ public int getStreamingServices(String appName, int subscriptionId,
+ List<String> serviceClasses) throws RemoteException {
return 0;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7c74729..c53f5d3 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -34,6 +34,7 @@
import android.telephony.NetworkScanRequest;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
import com.android.ims.internal.IImsServiceController;
@@ -1343,4 +1344,15 @@
* @hide
*/
boolean getEmergencyCallbackMode(int subId);
+
+ /**
+ * Get the most recently available signal strength information.
+ *
+ * Get the most recent SignalStrength information reported by the modem. Due
+ * to power saving this information may not always be current.
+ * @param subId Subscription index
+ * @return the most recent cached signal strength info from the modem
+ * @hide
+ */
+ SignalStrength getSignalStrength(int subId);
}
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index 50eaafb..7313a28 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -20,8 +20,7 @@
import android.content.Context;
import android.os.PerformanceCollector.PerformanceResultsWriter;
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestListener;
@@ -48,7 +47,7 @@
private Context mContext;
private boolean mSkipExecution = false;
- private List<TestListener> mTestListeners = Lists.newArrayList();
+ private List<TestListener> mTestListeners = new ArrayList<>();
private Instrumentation mInstrumentation;
private PerformanceResultsWriter mPerfWriter;
@@ -58,7 +57,8 @@
if (shouldRunSingleTestMethod(testMethodName, testClass)) {
TestCase testCase = buildSingleTestMethod(testClass, testMethodName);
- mTestCases = Lists.newArrayList(testCase);
+ mTestCases = new ArrayList<>();
+ mTestCases.add(testCase);
mTestClassName = testClass.getSimpleName();
} else {
setTest(getTest(testClass), testClass);
diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
index 1ab7c7f..2cf76af 100644
--- a/test-runner/src/android/test/ClassPathPackageInfo.java
+++ b/test-runner/src/android/test/ClassPathPackageInfo.java
@@ -16,9 +16,8 @@
package android.test;
-import com.google.android.collect.Sets;
-
import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
/**
@@ -44,7 +43,7 @@
}
public Set<ClassPathPackageInfo> getSubpackages() {
- Set<ClassPathPackageInfo> info = Sets.newHashSet();
+ Set<ClassPathPackageInfo> info = new HashSet<>();
for (String name : subpackageNames) {
info.add(source.getPackageInfo(name));
}
@@ -52,7 +51,7 @@
}
public Set<Class<?>> getTopLevelClassesRecursive() {
- Set<Class<?>> set = Sets.newHashSet();
+ Set<Class<?>> set = new HashSet<>();
addTopLevelClassesTo(set);
return set;
}
diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
index 89bb494..9bcc25a 100644
--- a/test-runner/src/android/test/ClassPathPackageInfoSource.java
+++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java
@@ -17,13 +17,13 @@
package android.test;
import android.util.Log;
-import com.google.android.collect.Maps;
-import com.google.android.collect.Sets;
import dalvik.system.DexFile;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -57,7 +57,7 @@
private static String[] apkPaths;
// A cache of jar file contents
- private final Map<File, Set<String>> jarFiles = Maps.newHashMap();
+ private final Map<File, Set<String>> jarFiles = new HashMap<>();
private ClassLoader classLoader;
ClassPathPackageInfoSource() {
@@ -76,7 +76,7 @@
private ClassPathPackageInfo createPackageInfo(String packageName) {
Set<String> subpackageNames = new TreeSet<String>();
Set<String> classNames = new TreeSet<String>();
- Set<Class<?>> topLevelClasses = Sets.newHashSet();
+ Set<Class<?>> topLevelClasses = new HashSet<>();
findClasses(packageName, classNames, subpackageNames);
for (String className : classNames) {
if (className.endsWith(".R") || className.endsWith(".Manifest")) {
@@ -248,7 +248,7 @@
throws IOException {
Set<String> entryNames = jarFiles.get(jarFile);
if (entryNames == null) {
- entryNames = Sets.newHashSet();
+ entryNames = new HashSet<>();
ZipFile zipFile = new ZipFile(jarFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
index 42ef48b..1980d92 100644
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ b/test-runner/src/android/test/DatabaseTestUtils.java
@@ -16,11 +16,10 @@
package android.test;
-import com.google.android.collect.Sets;
-
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
+import java.util.HashSet;
import java.util.Set;
/**
@@ -42,7 +41,7 @@
}
private static Set<String> getSchemaSet(SQLiteDatabase db) {
- Set<String> schemaSet = Sets.newHashSet();
+ Set<String> schemaSet = new HashSet<>();
Cursor entityCursor = db.rawQuery("SELECT sql FROM sqlite_master", null);
try {
diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
index 3abf38f..0b77c00 100644
--- a/test-runner/src/android/test/IsolatedContext.java
+++ b/test-runner/src/android/test/IsolatedContext.java
@@ -16,8 +16,6 @@
package android.test;
-import com.google.android.collect.Lists;
-
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
@@ -38,6 +36,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.List;
@@ -55,7 +54,7 @@
private ContentResolver mResolver;
private final MockAccountManager mMockAccountManager;
- private List<Intent> mBroadcastIntents = Lists.newArrayList();
+ private List<Intent> mBroadcastIntents = new ArrayList<>();
public IsolatedContext(
ContentResolver resolver, Context targetContext) {
@@ -67,7 +66,7 @@
/** Returns the list of intents that were broadcast since the last call to this method. */
public List<Intent> getAndClearBroadcastIntents() {
List<Intent> intents = mBroadcastIntents;
- mBroadcastIntents = Lists.newArrayList();
+ mBroadcastIntents = new ArrayList<>();
return intents;
}
diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
index 36786b0..fd33321 100644
--- a/test-runner/src/android/test/RenamingDelegatingContext.java
+++ b/test-runner/src/android/test/RenamingDelegatingContext.java
@@ -16,20 +16,24 @@
package android.test;
-import com.google.android.collect.Sets;
-
import android.content.Context;
import android.content.ContextWrapper;
import android.content.ContentProvider;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
-import android.os.FileUtils;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.EnumSet;
+import java.util.HashSet;
import java.util.Set;
/**
@@ -48,8 +52,8 @@
private File mCacheDir;
private final Object mSync = new Object();
- private Set<String> mDatabaseNames = Sets.newHashSet();
- private Set<String> mFileNames = Sets.newHashSet();
+ private Set<String> mDatabaseNames = new HashSet<>();
+ private Set<String> mFileNames = new HashSet<>();
public static <T extends ContentProvider> T providerWithRenamedContext(
Class<T> contentProvider, Context c, String filePrefix)
@@ -237,10 +241,14 @@
Log.w("RenamingDelegatingContext", "Unable to create cache directory");
return null;
}
- FileUtils.setPermissions(
- mCacheDir.getPath(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- -1, -1);
+ try {
+ // Give the directory all possible permissions.
+ Files.setPosixFilePermissions(mCacheDir.toPath(),
+ EnumSet.allOf(PosixFilePermission.class));
+ } catch (IOException e) {
+ Log.e("RenamingDelegatingContext",
+ "Could not set permissions of test cacheDir", e);
+ }
}
}
return mCacheDir;
diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
index c46d403..dc053a2 100644
--- a/test-runner/src/android/test/TestCaseUtil.java
+++ b/test-runner/src/android/test/TestCaseUtil.java
@@ -16,8 +16,7 @@
package android.test;
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
@@ -44,7 +43,7 @@
@SuppressWarnings("unchecked")
public static List<String> getTestCaseNames(Test test, boolean flatten) {
List<Test> tests = (List<Test>) getTests(test, flatten);
- List<String> testCaseNames = Lists.newArrayList();
+ List<String> testCaseNames = new ArrayList<>();
for (Test aTest : tests) {
testCaseNames.add(getTestName(aTest));
}
@@ -57,7 +56,7 @@
private static List<? extends Test> getTests(Test test, boolean flatten,
Set<Class<?>> seen) {
- List<Test> testCases = Lists.newArrayList();
+ List<Test> testCases = new ArrayList<>();
if (test != null) {
Test workingTest = null;
diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
index beecc6f..ff045c3 100644
--- a/test-runner/src/android/test/TestRunner.java
+++ b/test-runner/src/android/test/TestRunner.java
@@ -32,7 +32,6 @@
import junit.framework.TestListener;
import junit.framework.Test;
import junit.framework.TestResult;
-import com.google.android.collect.Lists;
/**
* Support class that actually runs a test. Android uses this class,
@@ -54,7 +53,7 @@
private int mMode = REGRESSION;
- private List<Listener> mListeners = Lists.newArrayList();
+ private List<Listener> mListeners = new ArrayList<>();
private int mPassed;
private int mFailed;
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index d8e0977..a70152c 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -23,8 +23,7 @@
import android.database.ContentObserver;
import android.net.Uri;
-import com.google.android.collect.Maps;
-
+import java.util.HashMap;
import java.util.Map;
/**
@@ -67,7 +66,7 @@
*/
public MockContentResolver(Context context) {
super(context);
- mProviders = Maps.newHashMap();
+ mProviders = new HashMap<>();
}
/**
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 3b920cf..cf6936b 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -21,7 +21,6 @@
import android.test.TestCaseUtil;
import android.util.Log;
import com.android.internal.util.Predicate;
-import com.google.android.collect.Lists;
import static android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME;
import static android.test.suitebuilder.TestPredicates.REJECT_SUPPRESSED;
@@ -69,7 +68,7 @@
public TestSuiteBuilder(String name, ClassLoader classLoader) {
this.suiteName = name;
this.testGrouping.setClassLoader(classLoader);
- this.testCases = Lists.newArrayList();
+ this.testCases = new ArrayList<>();
addRequirements(REJECT_SUPPRESSED);
}
diff --git a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
index 0574704..6723548 100644
--- a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
@@ -19,8 +19,7 @@
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.SmallTest;
-import com.google.android.collect.Lists;
-
+import java.util.ArrayList;
import junit.framework.TestCase;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
@@ -140,7 +139,7 @@
public void testSetTestClassWithTestSuiteProvider() throws Exception {
mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null);
List<TestCase> testCases = mAndroidTestRunner.getTestCases();
- List<String> testNames = Lists.newArrayList();
+ List<String> testNames = new ArrayList<>();
for (TestCase testCase : testCases) {
testNames.add(testCase.getName());
}
@@ -152,7 +151,7 @@
public void testSetTestClassWithTestSuite() throws Exception {
mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null);
List<TestCase> testCases = mAndroidTestRunner.getTestCases();
- List<String> testNames = Lists.newArrayList();
+ List<String> testNames = new ArrayList<>();
for (TestCase testCase : testCases) {
testNames.add(testCase.getName());
}
@@ -163,7 +162,7 @@
String testMethodName = "testTwo";
mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName);
List<TestCase> testCases = mAndroidTestRunner.getTestCases();
- List<String> testNames = Lists.newArrayList();
+ List<String> testNames = new ArrayList<>();
for (TestCase testCase : testCases) {
testNames.add(testCase.getName());
}
@@ -255,7 +254,7 @@
}
private static class TestListenerStub implements TestListener {
- List<String> testNames = Lists.newArrayList();
+ List<String> testNames = new ArrayList<>();
public void addError(Test test, Throwable t) {
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index ceb0135..cc792cc 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -45,6 +45,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.PendingIntent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.content.Context;
@@ -66,8 +67,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ConnectivityManagerTest {
@@ -296,6 +295,43 @@
manager.requestNetwork(request, callback);
}
+ @Test
+ public void testArgumentValidation() throws Exception {
+ ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
+
+ NetworkRequest request = mock(NetworkRequest.class);
+ NetworkCallback callback = mock(NetworkCallback.class);
+ Handler handler = mock(Handler.class);
+ NetworkCallback nullCallback = null;
+ PendingIntent nullIntent = null;
+
+ mustFail(() -> { manager.requestNetwork(null, callback); });
+ mustFail(() -> { manager.requestNetwork(request, nullCallback); });
+ mustFail(() -> { manager.requestNetwork(request, callback, null); });
+ mustFail(() -> { manager.requestNetwork(request, callback, -1); });
+ mustFail(() -> { manager.requestNetwork(request, nullIntent); });
+
+ mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); });
+ mustFail(() -> { manager.registerNetworkCallback(request, null, handler); });
+ mustFail(() -> { manager.registerNetworkCallback(request, callback, null); });
+ mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); });
+
+ mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
+ mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
+
+ mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
+ mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
+ mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
+ }
+
+ static void mustFail(Runnable fn) {
+ try {
+ fn.run();
+ fail();
+ } catch (Exception expected) {
+ }
+ }
+
static Message makeMessage(NetworkRequest req, int messageType) {
Bundle bundle = new Bundle();
bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 46dcdad..0099861 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -44,6 +44,7 @@
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback;
+import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.IpPrefix;
@@ -3055,7 +3056,7 @@
networkCallbacks.add(networkCallback);
}
fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
- } catch (IllegalArgumentException expected) {}
+ } catch (TooManyRequestsException expected) {}
for (NetworkCallback networkCallback : networkCallbacks) {
mCm.unregisterNetworkCallback(networkCallback);
}
@@ -3068,7 +3069,7 @@
networkCallbacks.add(networkCallback);
}
fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
- } catch (IllegalArgumentException expected) {}
+ } catch (TooManyRequestsException expected) {}
for (NetworkCallback networkCallback : networkCallbacks) {
mCm.unregisterNetworkCallback(networkCallback);
}
@@ -3084,7 +3085,7 @@
}
fail("Registering " + MAX_REQUESTS +
" PendingIntent NetworkRequests did not throw exception");
- } catch (IllegalArgumentException expected) {}
+ } catch (TooManyRequestsException expected) {}
for (PendingIntent pendingIntent : pendingIntents) {
mCm.unregisterNetworkCallback(pendingIntent);
}
@@ -3099,7 +3100,7 @@
}
fail("Registering " + MAX_REQUESTS +
" PendingIntent NetworkCallbacks did not throw exception");
- } catch (IllegalArgumentException expected) {}
+ } catch (TooManyRequestsException expected) {}
for (PendingIntent pendingIntent : pendingIntents) {
mCm.unregisterNetworkCallback(pendingIntent);
}
diff --git a/tests/testables/Android.mk b/tests/testables/Android.mk
index 759bc35..0e36981 100644
--- a/tests/testables/Android.mk
+++ b/tests/testables/Android.mk
@@ -31,3 +31,5 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java
index 13056cf..fe97bca1 100644
--- a/tests/testables/src/android/testing/TestableSettingsProvider.java
+++ b/tests/testables/src/android/testing/TestableSettingsProvider.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.test.mock.MockContentProvider;
import android.util.Log;
@@ -48,9 +49,10 @@
}
void clearValuesAndCheck(Context context) {
- mValues.put(key("global", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
- mValues.put(key("secure", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
- mValues.put(key("system", MY_UNIQUE_KEY), MY_UNIQUE_KEY);
+ int userId = UserHandle.myUserId();
+ mValues.put(key("global", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
+ mValues.put(key("secure", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
+ mValues.put(key("system", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
// Verify that if any test is using TestableContext, they all have the correct settings
// provider.
@@ -66,11 +68,12 @@
public Bundle call(String method, String arg, Bundle extras) {
// Methods are "GET_system", "GET_global", "PUT_secure", etc.
+ final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, 0);
final String[] commands = method.split("_", 2);
final String op = commands[0];
final String table = commands[1];
- String k = key(table, arg);
+ String k = key(table, arg, userId);
String value;
Bundle out = new Bundle();
switch (op) {
@@ -103,8 +106,13 @@
return out;
}
- private static String key(String table, String key) {
- return table + "_" + key;
+ private static String key(String table, String key, int userId) {
+ if ("global".equals(table)) {
+ return table + "_" + key;
+ } else {
+ return table + "_" + userId + "_" + key;
+ }
+
}
/**
diff --git a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
index 1f71867..0e2cc57 100644
--- a/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
+++ b/tests/testables/tests/src/android/testing/TestableSettingsProviderTest.java
@@ -66,6 +66,16 @@
}
@Test
+ public void testSeparateUsers() {
+ Secure.putStringForUser(mContentResolver, NONEXISTENT_SETTING, "something", 0);
+ Secure.putStringForUser(mContentResolver, NONEXISTENT_SETTING, "else", 1);
+ assertEquals("something",
+ Secure.getStringForUser(mContentResolver, NONEXISTENT_SETTING, 0));
+ assertEquals("else",
+ Secure.getStringForUser(mContentResolver, NONEXISTENT_SETTING, 1));
+ }
+
+ @Test
public void testPassThrough() {
// Grab the value of a setting that is not overridden.
assertTrue(Secure.getInt(mContentResolver, Secure.USER_SETUP_COMPLETE, 0) != 0);
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 15648bd..ba73180 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -762,6 +762,15 @@
return 1;
}
+ // Now add any dependencies passed in.
+ for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
+ const String8& assetPath = bundle->getPackageIncludes()[i];
+ if (!assets.addAssetPath(assetPath, NULL)) {
+ fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.string());
+ return 1;
+ }
+ }
+
// Make a dummy config for retrieving resources... we need to supply
// non-default values for some configs so that we can retrieve resources
// in the app that don't have a default. The most important of these is
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 01930d0..e45d142 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -27,7 +27,7 @@
static const char* sMajorVersion = "2";
// Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "14";
+static const char* sMinorVersion = "15";
int PrintVersion() {
std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 5413b33..c192d69 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -114,6 +114,7 @@
std::string output_path;
Maybe<std::string> res_dir;
bool pseudolocalize = false;
+ bool no_png_crunch = false;
bool legacy_mode = false;
bool verbose = false;
};
@@ -663,6 +664,7 @@
"Generate resources for pseudo-locales "
"(en-XA and ar-XB)",
&options.pseudolocalize)
+ .OptionalSwitch("--no-crunch", "Disables PNG processing", &options.no_png_crunch)
.OptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
&options.legacy_mode)
.OptionalSwitch("-v", "Enables verbose logging", &verbose);
@@ -738,7 +740,8 @@
if (!CompileXml(&context, options, path_data, archive_writer.get(), output_filename)) {
error = true;
}
- } else if (path_data.extension == "png" || path_data.extension == "9.png") {
+ } else if (!options.no_png_crunch &&
+ (path_data.extension == "png" || path_data.extension == "9.png")) {
if (!CompilePng(&context, options, path_data, archive_writer.get(), output_filename)) {
error = true;
}
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 0291720..e92565f 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,5 +1,13 @@
# Android Asset Packaging Tool 2.0 (AAPT2) release notes
+## Version 2.15
+### `aapt2 compile ...`
+- Add `--no-crunch` option to avoid processing PNGs during the compile phase. Note that this
+ shouldn't be used as a performance optimization, as once the PNG is processed, its result is
+ cached for incremental linking. This should only be used if the developer has specially
+ pre-processed the PNG and wants it byte-for-byte identical to the input.
+ NOTE: 9-patches will not be processed correctly with this flag set.
+
## Version 2.14
### `aapt2 link ...`
- If an app is building with a minSdkVersion < 26 and a --package-id XX where XX > 7F, aapt2
diff --git a/vr/Android.mk b/vr/Android.mk
new file mode 100644
index 0000000..5b65d3f
--- /dev/null
+++ b/vr/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LOCAL_PATH := $(call my-dir)
+
+# Library to perform dlopen on the actual shared library.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdvr_loader
+LOCAL_MODULE_OWNER := google
+LOCAL_SRC_FILES := dvr_library_loader.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+# Java platform library for vr stuff.
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.google.vr.platform
+LOCAL_MODULE_OWNER := google
+LOCAL_REQUIRED_MODULES := libdvr_loader libdvr
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.google.vr.platform.xml
+LOCAL_SRC_FILES := com.google.vr.platform.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_OWNER := google
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+include $(BUILD_PREBUILT)
diff --git a/vr/com.google.vr.platform.xml b/vr/com.google.vr.platform.xml
new file mode 100644
index 0000000..952b476
--- /dev/null
+++ b/vr/com.google.vr.platform.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <library name="com.google.vr.platform"
+ file="/system/framework/com.google.vr.platform.jar" />
+</permissions>
diff --git a/vr/dvr_library_loader.cpp b/vr/dvr_library_loader.cpp
new file mode 100644
index 0000000..0b4298a
--- /dev/null
+++ b/vr/dvr_library_loader.cpp
@@ -0,0 +1,25 @@
+#include <dlfcn.h>
+#include <jni.h>
+
+#include <string>
+
+extern "C" {
+
+JNIEXPORT jlong JNICALL
+Java_com_google_vr_platform_Dvr_nativeLoadLibrary(
+ JNIEnv* env, jclass, jstring java_library) {
+ if (!java_library)
+ return 0;
+
+ // Convert the Java String object to a C++ null-terminated string.
+ const char* data = env->GetStringUTFChars(java_library, NULL);
+ size_t size = env->GetStringUTFLength(java_library);
+ std::string library(data, size);
+ env->ReleaseStringUTFChars(java_library, data);
+
+ // Return the handle to the requested library.
+ return reinterpret_cast<jlong>(
+ dlopen(library.c_str(), RTLD_NOW | RTLD_LOCAL));
+}
+
+} // extern "C"
diff --git a/vr/java/com/google/vr/platform/DeviceInfo.java b/vr/java/com/google/vr/platform/DeviceInfo.java
new file mode 100644
index 0000000..f6da66b
--- /dev/null
+++ b/vr/java/com/google/vr/platform/DeviceInfo.java
@@ -0,0 +1,19 @@
+package com.google.vr.platform;
+
+import android.os.SystemProperties;
+
+/**
+ * Class to get information about the vr device.
+ * @hide
+ */
+public class DeviceInfo {
+
+ private static final String VR_MODE_BOOT = "ro.boot.vr";
+
+ /**
+ * Returns true if this device boots directly in VR mode.
+ */
+ public static boolean getVrBoot() {
+ return SystemProperties.getBoolean(VR_MODE_BOOT, false);
+ }
+}
diff --git a/vr/java/com/google/vr/platform/Dvr.java b/vr/java/com/google/vr/platform/Dvr.java
new file mode 100644
index 0000000..b07d634
--- /dev/null
+++ b/vr/java/com/google/vr/platform/Dvr.java
@@ -0,0 +1,22 @@
+package com.google.vr.platform;
+
+/**
+ * Class to load the dvr api.
+ * @hide
+ */
+public class Dvr {
+ /**
+ * Opens a shared library containing the dvr api and returns the handle to it.
+ *
+ * @return A Long object describing the handle returned by dlopen.
+ */
+ public static Long loadLibrary() {
+ // Load a thin JNI library that runs dlopen on request.
+ System.loadLibrary("dvr_loader");
+
+ // Performs dlopen on the library and returns the handle.
+ return nativeLoadLibrary("libdvr.so");
+ }
+
+ private static native long nativeLoadLibrary(String library);
+}