Merge "Update interface quota on the handler" into nyc-dev
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7bf03de..a82b950 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2578,9 +2578,10 @@
return true;
}
- case START_LOCK_TASK_BY_CURRENT_TRANSACTION: {
+ case START_SYSTEM_LOCK_TASK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- startLockTaskModeOnCurrent();
+ int taskId = data.readInt();
+ startSystemLockTaskMode(taskId);
reply.writeNoException();
return true;
}
@@ -2592,9 +2593,9 @@
return true;
}
- case STOP_LOCK_TASK_BY_CURRENT_TRANSACTION: {
+ case STOP_SYSTEM_LOCK_TASK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- stopLockTaskModeOnCurrent();
+ stopSystemLockTaskMode();
reply.writeNoException();
return true;
}
@@ -6386,11 +6387,12 @@
}
@Override
- public void startLockTaskModeOnCurrent() throws RemoteException {
+ public void startSystemLockTaskMode(int taskId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(START_LOCK_TASK_BY_CURRENT_TRANSACTION, data, reply, 0);
+ data.writeInt(taskId);
+ mRemote.transact(START_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
@@ -6408,11 +6410,11 @@
}
@Override
- public void stopLockTaskModeOnCurrent() throws RemoteException {
+ public void stopSystemLockTaskMode() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(STOP_LOCK_TASK_BY_CURRENT_TRANSACTION, data, reply, 0);
+ mRemote.transact(STOP_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6975116..1a4e98c 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -555,7 +555,7 @@
public int getActivityDisplayId(IBinder activityToken) throws RemoteException;
- public void startLockTaskModeOnCurrent() throws RemoteException;
+ public void startSystemLockTaskMode(int taskId) throws RemoteException;
public void startLockTaskMode(int taskId) throws RemoteException;
@@ -563,7 +563,7 @@
public void stopLockTaskMode() throws RemoteException;
- public void stopLockTaskModeOnCurrent() throws RemoteException;
+ public void stopSystemLockTaskMode() throws RemoteException;
public boolean isInLockTaskMode() throws RemoteException;
@@ -949,8 +949,8 @@
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
- int START_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+221;
- int STOP_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222;
+ int START_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+221;
+ int STOP_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222;
int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223;
int IS_TOP_OF_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+224;
int REQUEST_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+225;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index aef92cf..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -29,7 +29,6 @@
import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
-import android.os.Trace;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.LocaleList;
@@ -431,44 +430,37 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
- "ResourcesManager#createBaseActivityResources");
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- if (DEBUG) {
- Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
- + " with key=" + key);
- }
-
- synchronized (this) {
- final ActivityResources activityResources =
- getOrCreateActivityResourcesStructLocked(
- activityToken);
-
- if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
- }
- }
-
- // Update any existing Activity Resources references.
- updateResourcesForActivity(activityToken, overrideConfig);
-
- // Now request an actual Resources object.
- return getOrCreateResources(activityToken, key, classLoader);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ if (DEBUG) {
+ Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ + " with key=" + key);
}
+
+ synchronized (this) {
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+ }
+
+ // Update any existing Activity Resources references.
+ updateResourcesForActivity(activityToken, overrideConfig);
+
+ // Now request an actual Resources object.
+ return getOrCreateResources(activityToken, key, classLoader);
}
/**
@@ -498,8 +490,8 @@
}
if (activityToken != null) {
- final ActivityResources activityResources =
- getOrCreateActivityResourcesStructLocked(activityToken);
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
// Clean up any dead references so they don't pile up.
ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -547,7 +539,6 @@
final String[] systemLocales = findSystemLocales
? AssetManager.getSystem().getLocales() : null;
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
-
// Avoid checking for non-pseudo-locales if we already know there were some from a previous
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -622,21 +613,16 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- return getOrCreateResources(activityToken, key, classLoader);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
- }
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ return getOrCreateResources(activityToken, key, classLoader);
}
/**
@@ -650,104 +636,93 @@
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
@Nullable Configuration overrideConfig) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
- "ResourcesManager#updateResourcesForActivity");
- synchronized (this) {
- final ActivityResources activityResources =
- getOrCreateActivityResourcesStructLocked(activityToken);
+ synchronized (this) {
+ final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+ activityToken);
- if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
- // They are the same, no work to do.
- return;
+ if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+ // They are the same, no work to do.
+ return;
+ }
+
+ // Grab a copy of the old configuration so we can create the delta's of each
+ // Resources object associated with this Activity.
+ final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+
+ // Update the Activity's base override.
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+
+ if (DEBUG) {
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.d(TAG, "updating resources override for activity=" + activityToken
+ + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+ + " to newConfig="
+ + Configuration.resourceQualifierString(activityResources.overrideConfig),
+ here);
+ }
+
+ final boolean activityHasOverrideConfig =
+ !activityResources.overrideConfig.equals(Configuration.EMPTY);
+
+ // Rebase each Resources associated with this Activity.
+ final int refCount = activityResources.activityResources.size();
+ for (int i = 0; i < refCount; i++) {
+ WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
+ Resources resources = weakResRef.get();
+ if (resources == null) {
+ continue;
}
- // Grab a copy of the old configuration so we can create the delta's of each
- // Resources object associated with this Activity.
- final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+ // Extract the ResourcesKey that was last used to create the Resources for this
+ // activity.
+ final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+ if (oldKey == null) {
+ Slog.e(TAG, "can't find ResourcesKey for resources impl="
+ + resources.getImpl());
+ continue;
+ }
- // Update the Activity's base override.
+ // Build the new override configuration for this ResourcesKey.
+ final Configuration rebasedOverrideConfig = new Configuration();
if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
+ rebasedOverrideConfig.setTo(overrideConfig);
}
+ if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+ // Generate a delta between the old base Activity override configuration and
+ // the actual final override configuration that was used to figure out the real
+ // delta this Resources object wanted.
+ Configuration overrideOverrideConfig = Configuration.generateDelta(
+ oldConfig, oldKey.mOverrideConfiguration);
+ rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ }
+
+ // Create the new ResourcesKey with the rebased override config.
+ final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
+ oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+ rebasedOverrideConfig, oldKey.mCompatInfo);
+
if (DEBUG) {
- Throwable here = new Throwable();
- here.fillInStackTrace();
- Slog.d(TAG, "updating resources override for activity=" + activityToken
- + " from oldConfig="
- + Configuration.resourceQualifierString(oldConfig)
- + " to newConfig="
- + Configuration.resourceQualifierString(
- activityResources.overrideConfig),
- here);
+ Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+ + " to newKey=" + newKey);
}
- final boolean activityHasOverrideConfig =
- !activityResources.overrideConfig.equals(Configuration.EMPTY);
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl == null) {
+ resourcesImpl = createResourcesImpl(newKey);
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ }
- // Rebase each Resources associated with this Activity.
- final int refCount = activityResources.activityResources.size();
- for (int i = 0; i < refCount; i++) {
- WeakReference<Resources> weakResRef = activityResources.activityResources.get(
- i);
- Resources resources = weakResRef.get();
- if (resources == null) {
- continue;
- }
-
- // Extract the ResourcesKey that was last used to create the Resources for this
- // activity.
- final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
- if (oldKey == null) {
- Slog.e(TAG, "can't find ResourcesKey for resources impl="
- + resources.getImpl());
- continue;
- }
-
- // Build the new override configuration for this ResourcesKey.
- final Configuration rebasedOverrideConfig = new Configuration();
- if (overrideConfig != null) {
- rebasedOverrideConfig.setTo(overrideConfig);
- }
-
- if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
- // Generate a delta between the old base Activity override configuration and
- // the actual final override configuration that was used to figure out the
- // real delta this Resources object wanted.
- Configuration overrideOverrideConfig = Configuration.generateDelta(
- oldConfig, oldKey.mOverrideConfiguration);
- rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
- }
-
- // Create the new ResourcesKey with the rebased override config.
- final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
- oldKey.mSplitResDirs,
- oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
- rebasedOverrideConfig, oldKey.mCompatInfo);
-
- if (DEBUG) {
- Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
- + " to newKey=" + newKey);
- }
-
- ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
- if (resourcesImpl == null) {
- resourcesImpl = createResourcesImpl(newKey);
- mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
- }
-
- if (resourcesImpl != resources.getImpl()) {
- // Set the ResourcesImpl, updating it for all users of this Resources
- // object.
- resources.setImpl(resourcesImpl);
- }
+ if (resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources object.
+ resources.setImpl(resourcesImpl);
}
}
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
@@ -770,95 +745,86 @@
public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
@Nullable CompatibilityInfo compat) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
- "ResourcesManager#applyConfigurationToResourcesLocked");
-
- if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
- + mResConfiguration.seq + ", newSeq=" + config.seq);
- return false;
- }
- int changes = mResConfiguration.updateFrom(config);
- // Things might have changed in display manager, so clear the cached displays.
- mDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
-
- if (compat != null && (mResCompatibilityInfo == null ||
- !mResCompatibilityInfo.equals(compat))) {
- mResCompatibilityInfo = compat;
- changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- }
-
- Configuration localeAdjustedConfig = config;
- final LocaleList configLocales = config.getLocales();
- if (!configLocales.isEmpty()) {
- setDefaultLocalesLocked(configLocales);
- final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
- if (adjustedLocales
- != configLocales) { // has the same result as .equals() in this case
- // The first locale in the list was not chosen. So we create a modified
- // configuration with the adjusted locales (which moves the chosen locale to the
- // front).
- localeAdjustedConfig = new Configuration();
- localeAdjustedConfig.setTo(config);
- localeAdjustedConfig.setLocales(adjustedLocales);
- // Also adjust the locale list in mResConfiguration, so that the Resources
- // created later would have the same locale list.
- if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
- mResConfiguration.setLocales(adjustedLocales);
- changes |= ActivityInfo.CONFIG_LOCALE;
- }
- }
- }
-
- Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
- compat);
-
- ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
-
- Configuration tmpConfig = null;
-
- for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
- ResourcesKey key = mResourceImpls.keyAt(i);
- ResourcesImpl r = mResourceImpls.valueAt(i).get();
- if (r != null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + localeAdjustedConfig);
- int displayId = key.mDisplayId;
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- DisplayMetrics dm = defaultDisplayMetrics;
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
- if (!isDefaultDisplay || hasOverrideConfiguration) {
- if (tmpConfig == null) {
- tmpConfig = new Configuration();
- }
- tmpConfig.setTo(localeAdjustedConfig);
- if (!isDefaultDisplay) {
- dm = getDisplayMetrics(displayId);
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
- }
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
- r.updateConfiguration(tmpConfig, dm, compat);
- } else {
- r.updateConfiguration(localeAdjustedConfig, dm, compat);
- }
- //Slog.i(TAG, "Updated app resources " + v.getKey()
- // + " " + r + ": " + r.getConfiguration());
- } else {
- //Slog.i(TAG, "Removing old resources " + v.getKey());
- mResourceImpls.removeAt(i);
- }
- }
-
- return changes != 0;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ + mResConfiguration.seq + ", newSeq=" + config.seq);
+ return false;
}
+ int changes = mResConfiguration.updateFrom(config);
+ // Things might have changed in display manager, so clear the cached displays.
+ mDisplays.clear();
+ DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
+
+ if (compat != null && (mResCompatibilityInfo == null ||
+ !mResCompatibilityInfo.equals(compat))) {
+ mResCompatibilityInfo = compat;
+ changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+
+ Configuration localeAdjustedConfig = config;
+ final LocaleList configLocales = config.getLocales();
+ if (!configLocales.isEmpty()) {
+ setDefaultLocalesLocked(configLocales);
+ final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+ if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
+ // The first locale in the list was not chosen. So we create a modified
+ // configuration with the adjusted locales (which moves the chosen locale to the
+ // front).
+ localeAdjustedConfig = new Configuration();
+ localeAdjustedConfig.setTo(config);
+ localeAdjustedConfig.setLocales(adjustedLocales);
+ // Also adjust the locale list in mResConfiguration, so that the Resources created
+ // later would have the same locale list.
+ if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+ mResConfiguration.setLocales(adjustedLocales);
+ changes |= ActivityInfo.CONFIG_LOCALE;
+ }
+ }
+ }
+
+ Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
+
+ ApplicationPackageManager.configurationChanged();
+ //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+
+ Configuration tmpConfig = null;
+
+ for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+ ResourcesKey key = mResourceImpls.keyAt(i);
+ ResourcesImpl r = mResourceImpls.valueAt(i).get();
+ if (r != null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ + r + " config to: " + localeAdjustedConfig);
+ int displayId = key.mDisplayId;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ DisplayMetrics dm = defaultDisplayMetrics;
+ final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfiguration) {
+ if (tmpConfig == null) {
+ tmpConfig = new Configuration();
+ }
+ tmpConfig.setTo(localeAdjustedConfig);
+ if (!isDefaultDisplay) {
+ dm = getDisplayMetrics(displayId);
+ applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+ }
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(key.mOverrideConfiguration);
+ }
+ r.updateConfiguration(tmpConfig, dm, compat);
+ } else {
+ r.updateConfiguration(localeAdjustedConfig, dm, compat);
+ }
+ //Slog.i(TAG, "Updated app resources " + v.getKey()
+ // + " " + r + ": " + r.getConfiguration());
+ } else {
+ //Slog.i(TAG, "Removing old resources " + v.getKey());
+ mResourceImpls.removeAt(i);
+ }
+ }
+
+ return changes != 0;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 269089e..7a18df6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1093,6 +1093,7 @@
* returned.
*/
public List<ComponentName> getActiveAdmins() {
+ throwIfParentInstance("getActiveAdmins");
return getActiveAdminsAsUser(myUserId());
}
@@ -1149,6 +1150,7 @@
* @throws SecurityException if the caller is not in the owner application of {@code admin}.
*/
public void removeActiveAdmin(@NonNull ComponentName admin) {
+ throwIfParentInstance("removeActiveAdmin");
if (mService != null) {
try {
mService.removeActiveAdmin(admin, myUserId());
@@ -1169,6 +1171,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) {
+ throwIfParentInstance("hasGrantedPolicy");
if (mService != null) {
try {
return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
@@ -2216,9 +2219,7 @@
* that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
*/
public boolean resetPassword(String password, int flags) {
- if (mParentInstance) {
- throw new SecurityException("Reset password does not work across profiles.");
- }
+ throwIfParentInstance("resetPassword");
if (mService != null) {
try {
return mService.resetPassword(password, flags);
@@ -2355,6 +2356,7 @@
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
*/
public void wipeData(int flags) {
+ throwIfParentInstance("wipeData");
if (mService != null) {
try {
mService.wipeData(flags);
@@ -2388,6 +2390,7 @@
*/
public ComponentName setGlobalProxy(@NonNull ComponentName admin, Proxy proxySpec,
List<String> exclusionList ) {
+ throwIfParentInstance("setGlobalProxy");
if (proxySpec == null) {
throw new NullPointerException();
}
@@ -2453,6 +2456,7 @@
*/
public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo
proxyInfo) {
+ throwIfParentInstance("setRecommendedGlobalProxy");
if (mService != null) {
try {
mService.setRecommendedGlobalProxy(admin, proxyInfo);
@@ -2603,6 +2607,7 @@
* {@link DeviceAdminInfo#USES_ENCRYPTED_STORAGE}
*/
public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) {
+ throwIfParentInstance("setStorageEncryption");
if (mService != null) {
try {
return mService.setStorageEncryption(admin, encrypt);
@@ -2623,6 +2628,7 @@
* @return true if the admin(s) are requesting encryption, false if not.
*/
public boolean getStorageEncryption(@Nullable ComponentName admin) {
+ throwIfParentInstance("getStorageEncryption");
if (mService != null) {
try {
return mService.getStorageEncryption(admin, myUserId());
@@ -2653,6 +2659,7 @@
* or {@link #ENCRYPTION_STATUS_ACTIVE}.
*/
public int getStorageEncryptionStatus() {
+ throwIfParentInstance("getStorageEncryptionStatus");
return getStorageEncryptionStatus(myUserId());
}
@@ -2718,6 +2725,7 @@
* owner.
*/
public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
+ throwIfParentInstance("installCaCert");
if (mService != null) {
try {
return mService.installCaCert(admin, certBuffer);
@@ -2738,6 +2746,7 @@
* owner.
*/
public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
+ throwIfParentInstance("uninstallCaCert");
if (mService != null) {
try {
final String alias = getCaCertAlias(certBuffer);
@@ -2763,6 +2772,7 @@
*/
public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) {
List<byte[]> certs = new ArrayList<byte[]>();
+ throwIfParentInstance("getInstalledCaCerts");
if (mService != null) {
try {
mService.enforceCanManageCaCerts(admin);
@@ -2791,6 +2801,7 @@
* owner.
*/
public void uninstallAllUserCaCerts(@Nullable ComponentName admin) {
+ throwIfParentInstance("uninstallAllUserCaCerts");
if (mService != null) {
try {
mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
@@ -2811,6 +2822,7 @@
* owner.
*/
public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) {
+ throwIfParentInstance("hasCaCertInstalled");
if (mService != null) {
try {
mService.enforceCanManageCaCerts(admin);
@@ -2879,6 +2891,7 @@
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
+ throwIfParentInstance("installKeyPair");
try {
final byte[] pemCert = Credentials.convertToPem(certs[0]);
byte[] pemChain = null;
@@ -2911,6 +2924,7 @@
* owner.
*/
public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
+ throwIfParentInstance("removeKeyPair");
try {
return mService.removeKeyPair(admin, alias);
} catch (RemoteException e) {
@@ -2951,6 +2965,7 @@
*/
public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String
installerPackage) throws SecurityException {
+ throwIfParentInstance("setCertInstallerPackage");
if (mService != null) {
try {
mService.setCertInstallerPackage(admin, installerPackage);
@@ -2970,6 +2985,7 @@
* @throws SecurityException if {@code admin} is not a device or a profile owner.
*/
public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException {
+ throwIfParentInstance("getCertInstallerPackage");
if (mService != null) {
try {
return mService.getCertInstallerPackage(admin);
@@ -3000,6 +3016,7 @@
*/
public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage)
throws NameNotFoundException, UnsupportedOperationException {
+ throwIfParentInstance("setAlwaysOnVpnPackage");
if (mService != null) {
try {
if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage)) {
@@ -3021,6 +3038,7 @@
* @throws SecurityException if {@code admin} is not a device or a profile owner.
*/
public String getAlwaysOnVpnPackage(@NonNull ComponentName admin) {
+ throwIfParentInstance("getAlwaysOnVpnPackage");
if (mService != null) {
try {
return mService.getAlwaysOnVpnPackage(admin);
@@ -3048,6 +3066,7 @@
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
*/
public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setCameraDisabled");
if (mService != null) {
try {
mService.setCameraDisabled(admin, disabled);
@@ -3064,6 +3083,7 @@
* have disabled the camera
*/
public boolean getCameraDisabled(@Nullable ComponentName admin) {
+ throwIfParentInstance("getCameraDisabled");
return getCameraDisabled(admin, myUserId());
}
@@ -3093,6 +3113,7 @@
* than the one managed by the device owner.
*/
public boolean requestBugreport(@NonNull ComponentName admin) {
+ throwIfParentInstance("requestBugreport");
if (mService != null) {
try {
return mService.requestBugreport(admin);
@@ -3131,6 +3152,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setScreenCaptureDisabled");
if (mService != null) {
try {
mService.setScreenCaptureDisabled(admin, disabled);
@@ -3147,6 +3169,7 @@
* have disabled screen capture.
*/
public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) {
+ throwIfParentInstance("getScreenCaptureDisabled");
return getScreenCaptureDisabled(admin, myUserId());
}
@@ -3176,6 +3199,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) {
+ throwIfParentInstance("setAutoTimeRequired");
if (mService != null) {
try {
mService.setAutoTimeRequired(admin, required);
@@ -3189,6 +3213,7 @@
* @return true if auto time is required.
*/
public boolean getAutoTimeRequired() {
+ throwIfParentInstance("getAutoTimeRequired");
if (mService != null) {
try {
return mService.getAutoTimeRequired();
@@ -3215,6 +3240,7 @@
*/
public void setForceEphemeralUsers(
@NonNull ComponentName admin, boolean forceEphemeralUsers) {
+ throwIfParentInstance("setForceEphemeralUsers");
if (mService != null) {
try {
mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
@@ -3230,6 +3256,7 @@
* @hide
*/
public boolean getForceEphemeralUsers(@NonNull ComponentName admin) {
+ throwIfParentInstance("getForceEphemeralUsers");
if (mService != null) {
try {
return mService.getForceEphemeralUsers(admin);
@@ -3517,6 +3544,7 @@
* @return whether or not the package is registered as the device owner app.
*/
public boolean isDeviceOwnerApp(String packageName) {
+ throwIfParentInstance("isDeviceOwnerApp");
return isDeviceOwnerAppOnCallingUser(packageName);
}
@@ -3614,6 +3642,7 @@
* does not own the current device owner component.
*/
public void clearDeviceOwnerApp(String packageName) {
+ throwIfParentInstance("clearDeviceOwnerApp");
if (mService != null) {
try {
mService.clearDeviceOwner(packageName);
@@ -3632,6 +3661,7 @@
*/
@SystemApi
public String getDeviceOwner() {
+ throwIfParentInstance("getDeviceOwner");
final ComponentName name = getDeviceOwnerComponentOnCallingUser();
return name != null ? name.getPackageName() : null;
}
@@ -3657,6 +3687,7 @@
*/
@SystemApi
public String getDeviceOwnerNameOnAnyUser() {
+ throwIfParentInstance("getDeviceOwnerNameOnAnyUser");
if (mService != null) {
try {
return mService.getDeviceOwnerName();
@@ -3708,6 +3739,7 @@
@SystemApi
public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
throws IllegalArgumentException {
+ throwIfParentInstance("setActiveProfileOwner");
if (mService != null) {
try {
final int myUserId = myUserId();
@@ -3731,6 +3763,7 @@
* @throws SecurityException if {@code admin} is not an active profile owner.
*/
public void clearProfileOwner(@NonNull ComponentName admin) {
+ throwIfParentInstance("clearProfileOwner");
if (mService != null) {
try {
mService.clearProfileOwner(admin);
@@ -3804,6 +3837,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public void setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, CharSequence info) {
+ throwIfParentInstance("setDeviceOwnerLockScreenInfo");
if (mService != null) {
try {
mService.setDeviceOwnerLockScreenInfo(admin, info);
@@ -3817,6 +3851,7 @@
* @return The device owner information. If it is not set returns {@code null}.
*/
public CharSequence getDeviceOwnerLockScreenInfo() {
+ throwIfParentInstance("getDeviceOwnerLockScreenInfo");
if (mService != null) {
try {
return mService.getDeviceOwnerLockScreenInfo();
@@ -3848,6 +3883,7 @@
*/
public String[] setPackagesSuspended(@NonNull ComponentName admin, String[] packageNames,
boolean suspended) {
+ throwIfParentInstance("setPackagesSuspended");
if (mService != null) {
try {
return mService.setPackagesSuspended(admin, packageNames, suspended);
@@ -3870,6 +3906,7 @@
*/
public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName)
throws NameNotFoundException {
+ throwIfParentInstance("isPackageSuspended");
if (mService != null) {
try {
return mService.isPackageSuspended(admin, packageName);
@@ -3891,6 +3928,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public void setProfileEnabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("setProfileEnabled");
if (mService != null) {
try {
mService.setProfileEnabled(admin);
@@ -3912,6 +3950,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setProfileName(@NonNull ComponentName admin, String profileName) {
+ throwIfParentInstance("setProfileName");
if (mService != null) {
try {
mService.setProfileName(admin, profileName);
@@ -3930,6 +3969,7 @@
* @return Whether or not the package is registered as the profile owner.
*/
public boolean isProfileOwnerApp(String packageName) {
+ throwIfParentInstance("isProfileOwnerApp");
if (mService != null) {
try {
ComponentName profileOwner = mService.getProfileOwner(myUserId());
@@ -3950,6 +3990,7 @@
*/
@SystemApi
public ComponentName getProfileOwner() throws IllegalArgumentException {
+ throwIfParentInstance("getProfileOwner");
return getProfileOwnerAsUser(Process.myUserHandle().getIdentifier());
}
@@ -3994,6 +4035,7 @@
*/
@SystemApi
public String getProfileOwnerNameAsUser(int userId) throws IllegalArgumentException {
+ throwIfParentInstance("getProfileOwnerNameAsUser");
if (mService != null) {
try {
return mService.getProfileOwnerName(userId);
@@ -4024,6 +4066,7 @@
*/
public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter,
@NonNull ComponentName activity) {
+ throwIfParentInstance("addPersistentPreferredActivity");
if (mService != null) {
try {
mService.addPersistentPreferredActivity(admin, filter, activity);
@@ -4046,6 +4089,7 @@
*/
public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin,
String packageName) {
+ throwIfParentInstance("clearPackagePersistentPreferredActivities");
if (mService != null) {
try {
mService.clearPackagePersistentPreferredActivities(admin, packageName);
@@ -4074,6 +4118,7 @@
*/
public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin,
@Nullable String packageName) throws NameNotFoundException {
+ throwIfParentInstance("setApplicationRestrictionsManagingPackage");
if (mService != null) {
try {
if (!mService.setApplicationRestrictionsManagingPackage(admin, packageName)) {
@@ -4095,6 +4140,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) {
+ throwIfParentInstance("getApplicationRestrictionsManagingPackage");
if (mService != null) {
try {
return mService.getApplicationRestrictionsManagingPackage(admin);
@@ -4114,6 +4160,7 @@
* that method.
*/
public boolean isCallerApplicationRestrictionsManagingPackage() {
+ throwIfParentInstance("isCallerApplicationRestrictionsManagingPackage");
if (mService != null) {
try {
return mService.isCallerApplicationRestrictionsManagingPackage();
@@ -4159,6 +4206,7 @@
*/
public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
Bundle settings) {
+ throwIfParentInstance("setApplicationRestrictions");
if (mService != null) {
try {
mService.setApplicationRestrictions(admin, packageName, settings);
@@ -4257,6 +4305,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setCrossProfileCallerIdDisabled");
if (mService != null) {
try {
mService.setCrossProfileCallerIdDisabled(admin, disabled);
@@ -4277,6 +4326,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("getCrossProfileCallerIdDisabled");
if (mService != null) {
try {
return mService.getCrossProfileCallerIdDisabled(admin);
@@ -4317,6 +4367,7 @@
*/
public void setCrossProfileContactsSearchDisabled(@NonNull ComponentName admin,
boolean disabled) {
+ throwIfParentInstance("setCrossProfileContactsSearchDisabled");
if (mService != null) {
try {
mService.setCrossProfileContactsSearchDisabled(admin, disabled);
@@ -4337,6 +4388,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean getCrossProfileContactsSearchDisabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("getCrossProfileContactsSearchDisabled");
if (mService != null) {
try {
return mService.getCrossProfileContactsSearchDisabled(admin);
@@ -4407,6 +4459,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setBluetoothContactSharingDisabled");
if (mService != null) {
try {
mService.setBluetoothContactSharingDisabled(admin, disabled);
@@ -4429,6 +4482,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("getBluetoothContactSharingDisabled");
if (mService != null) {
try {
return mService.getBluetoothContactSharingDisabled(admin);
@@ -4472,6 +4526,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) {
+ throwIfParentInstance("addCrossProfileIntentFilter");
if (mService != null) {
try {
mService.addCrossProfileIntentFilter(admin, filter, flags);
@@ -4490,6 +4545,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) {
+ throwIfParentInstance("clearCrossProfileIntentFilters");
if (mService != null) {
try {
mService.clearCrossProfileIntentFilters(admin);
@@ -4519,6 +4575,7 @@
*/
public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin,
List<String> packageNames) {
+ throwIfParentInstance("setPermittedAccessibilityServices");
if (mService != null) {
try {
return mService.setPermittedAccessibilityServices(admin, packageNames);
@@ -4540,6 +4597,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) {
+ throwIfParentInstance("getPermittedAccessibilityServices");
if (mService != null) {
try {
return mService.getPermittedAccessibilityServices(admin);
@@ -4587,6 +4645,7 @@
*/
@SystemApi
public List<String> getPermittedAccessibilityServices(int userId) {
+ throwIfParentInstance("getPermittedAccessibilityServices");
if (mService != null) {
try {
return mService.getPermittedAccessibilityServicesForUser(userId);
@@ -4617,6 +4676,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) {
+ throwIfParentInstance("setPermittedInputMethods");
if (mService != null) {
try {
return mService.setPermittedInputMethods(admin, packageNames);
@@ -4639,6 +4699,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public List<String> getPermittedInputMethods(@NonNull ComponentName admin) {
+ throwIfParentInstance("getPermittedInputMethods");
if (mService != null) {
try {
return mService.getPermittedInputMethods(admin);
@@ -4684,6 +4745,7 @@
*/
@SystemApi
public List<String> getPermittedInputMethodsForCurrentUser() {
+ throwIfParentInstance("getPermittedInputMethodsForCurrentUser");
if (mService != null) {
try {
return mService.getPermittedInputMethodsForCurrentUser();
@@ -4704,6 +4766,7 @@
* @hide
*/
public List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) {
+ throwIfParentInstance("getKeepUninstalledPackages");
if (mService != null) {
try {
return mService.getKeepUninstalledPackages(admin);
@@ -4728,6 +4791,7 @@
*/
public void setKeepUninstalledPackages(@NonNull ComponentName admin,
@NonNull List<String> packageNames) {
+ throwIfParentInstance("setKeepUninstalledPackages");
if (mService != null) {
try {
mService.setKeepUninstalledPackages(admin, packageNames);
@@ -4834,6 +4898,7 @@
public UserHandle createAndManageUser(@NonNull ComponentName admin, @NonNull String name,
@NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras,
int flags) {
+ throwIfParentInstance("createAndManageUser");
try {
return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
} catch (RemoteException re) {
@@ -4851,6 +4916,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) {
+ throwIfParentInstance("removeUser");
try {
return mService.removeUser(admin, userHandle);
} catch (RemoteException re) {
@@ -4868,6 +4934,7 @@
* @see Intent#ACTION_USER_FOREGROUND
*/
public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) {
+ throwIfParentInstance("switchUser");
try {
return mService.switchUser(admin, userHandle);
} catch (RemoteException re) {
@@ -4893,6 +4960,7 @@
* @see {@link #setApplicationRestrictionsManagingPackage}
*/
public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) {
+ throwIfParentInstance("getApplicationRestrictions");
if (mService != null) {
try {
return mService.getApplicationRestrictions(admin, packageName);
@@ -4915,6 +4983,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void addUserRestriction(@NonNull ComponentName admin, String key) {
+ throwIfParentInstance("addUserRestriction");
if (mService != null) {
try {
mService.setUserRestriction(admin, key, true);
@@ -4936,6 +5005,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void clearUserRestriction(@NonNull ComponentName admin, String key) {
+ throwIfParentInstance("clearUserRestriction");
if (mService != null) {
try {
mService.setUserRestriction(admin, key, false);
@@ -4957,6 +5027,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public Bundle getUserRestrictions(@NonNull ComponentName admin) {
+ throwIfParentInstance("getUserRestrictions");
Bundle ret = null;
if (mService != null) {
try {
@@ -5001,6 +5072,7 @@
*/
public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
boolean hidden) {
+ throwIfParentInstance("setApplicationHidden");
if (mService != null) {
try {
return mService.setApplicationHidden(admin, packageName, hidden);
@@ -5020,6 +5092,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("isApplicationHidden");
if (mService != null) {
try {
return mService.isApplicationHidden(admin, packageName);
@@ -5039,6 +5112,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
mService.enableSystemApp(admin, packageName);
@@ -5059,6 +5133,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
+ throwIfParentInstance("enableSystemApp");
if (mService != null) {
try {
return mService.enableSystemAppWithIntent(admin, intent);
@@ -5091,6 +5166,7 @@
*/
public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType,
boolean disabled) {
+ throwIfParentInstance("setAccountManagementDisabled");
if (mService != null) {
try {
mService.setAccountManagementDisabled(admin, accountType, disabled);
@@ -5111,6 +5187,7 @@
* @see #setAccountManagementDisabled
*/
public String[] getAccountTypesWithManagementDisabled() {
+ throwIfParentInstance("getAccountTypesWithManagementDisabled");
return getAccountTypesWithManagementDisabledAsUser(myUserId());
}
@@ -5148,6 +5225,7 @@
*/
public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages)
throws SecurityException {
+ throwIfParentInstance("setLockTaskPackages");
if (mService != null) {
try {
mService.setLockTaskPackages(admin, packages);
@@ -5164,6 +5242,7 @@
* @hide
*/
public String[] getLockTaskPackages(@NonNull ComponentName admin) {
+ throwIfParentInstance("getLockTaskPackages");
if (mService != null) {
try {
return mService.getLockTaskPackages(admin);
@@ -5180,6 +5259,7 @@
* @param pkg The package to check
*/
public boolean isLockTaskPermitted(String pkg) {
+ throwIfParentInstance("isLockTaskPermitted");
if (mService != null) {
try {
return mService.isLockTaskPermitted(pkg);
@@ -5228,6 +5308,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) {
+ throwIfParentInstance("setGlobalSetting");
if (mService != null) {
try {
mService.setGlobalSetting(admin, setting, value);
@@ -5260,6 +5341,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) {
+ throwIfParentInstance("setSecureSetting");
if (mService != null) {
try {
mService.setSecureSetting(admin, setting, value);
@@ -5283,6 +5365,7 @@
*/
public void setRestrictionsProvider(@NonNull ComponentName admin,
@Nullable ComponentName provider) {
+ throwIfParentInstance("setRestrictionsProvider");
if (mService != null) {
try {
mService.setRestrictionsProvider(admin, provider);
@@ -5300,6 +5383,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) {
+ throwIfParentInstance("setMasterVolumeMuted");
if (mService != null) {
try {
mService.setMasterVolumeMuted(admin, on);
@@ -5317,6 +5401,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean isMasterVolumeMuted(@NonNull ComponentName admin) {
+ throwIfParentInstance("isMasterVolumeMuted");
if (mService != null) {
try {
return mService.isMasterVolumeMuted(admin);
@@ -5337,6 +5422,7 @@
*/
public void setUninstallBlocked(@NonNull ComponentName admin, String packageName,
boolean uninstallBlocked) {
+ throwIfParentInstance("setUninstallBlocked");
if (mService != null) {
try {
mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
@@ -5362,6 +5448,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) {
+ throwIfParentInstance("isUninstallBlocked");
if (mService != null) {
try {
return mService.isUninstallBlocked(admin, packageName);
@@ -5389,6 +5476,7 @@
* @see #getCrossProfileWidgetProviders(android.content.ComponentName)
*/
public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("addCrossProfileWidgetProvider");
if (mService != null) {
try {
return mService.addCrossProfileWidgetProvider(admin, packageName);
@@ -5416,6 +5504,7 @@
*/
public boolean removeCrossProfileWidgetProvider(
@NonNull ComponentName admin, String packageName) {
+ throwIfParentInstance("removeCrossProfileWidgetProvider");
if (mService != null) {
try {
return mService.removeCrossProfileWidgetProvider(admin, packageName);
@@ -5437,6 +5526,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) {
+ throwIfParentInstance("getCrossProfileWidgetProviders");
if (mService != null) {
try {
List<String> providers = mService.getCrossProfileWidgetProviders(admin);
@@ -5458,6 +5548,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) {
+ throwIfParentInstance("setUserIcon");
try {
mService.setUserIcon(admin, icon);
} catch (RemoteException re) {
@@ -5477,6 +5568,7 @@
* @see SystemUpdatePolicy
*/
public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) {
+ throwIfParentInstance("setSystemUpdatePolicy");
if (mService != null) {
try {
mService.setSystemUpdatePolicy(admin, policy);
@@ -5492,6 +5584,7 @@
* @return The current policy object, or {@code null} if no policy is set.
*/
public SystemUpdatePolicy getSystemUpdatePolicy() {
+ throwIfParentInstance("getSystemUpdatePolicy");
if (mService != null) {
try {
return mService.getSystemUpdatePolicy();
@@ -5517,6 +5610,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setKeyguardDisabled");
try {
return mService.setKeyguardDisabled(admin, disabled);
} catch (RemoteException re) {
@@ -5535,6 +5629,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) {
+ throwIfParentInstance("setStatusBarDisabled");
try {
return mService.setStatusBarDisabled(admin, disabled);
} catch (RemoteException re) {
@@ -5553,6 +5648,7 @@
*/
@SystemApi
public void notifyPendingSystemUpdate(long updateReceivedTime) {
+ throwIfParentInstance("notifyPendingSystemUpdate");
if (mService != null) {
try {
mService.notifyPendingSystemUpdate(updateReceivedTime);
@@ -5580,6 +5676,7 @@
* @see #setPermissionGrantState
*/
public void setPermissionPolicy(@NonNull ComponentName admin, int policy) {
+ throwIfParentInstance("setPermissionPolicy");
try {
mService.setPermissionPolicy(admin, policy);
} catch (RemoteException re) {
@@ -5594,6 +5691,7 @@
* @return the current policy for future permission requests.
*/
public int getPermissionPolicy(ComponentName admin) {
+ throwIfParentInstance("getPermissionPolicy");
try {
return mService.getPermissionPolicy(admin);
} catch (RemoteException re) {
@@ -5630,6 +5728,7 @@
*/
public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName,
String permission, int grantState) {
+ throwIfParentInstance("setPermissionGrantState");
try {
return mService.setPermissionGrantState(admin, packageName, permission, grantState);
} catch (RemoteException re) {
@@ -5658,6 +5757,7 @@
*/
public int getPermissionGrantState(@NonNull ComponentName admin, String packageName,
String permission) {
+ throwIfParentInstance("getPermissionGrantState");
try {
return mService.getPermissionGrantState(admin, packageName, permission);
} catch (RemoteException re) {
@@ -5673,6 +5773,7 @@
* @throws IllegalArgumentException if the supplied action is not valid.
*/
public boolean isProvisioningAllowed(String action) {
+ throwIfParentInstance("isProvisioningAllowed");
try {
return mService.isProvisioningAllowed(action);
} catch (RemoteException re) {
@@ -5688,6 +5789,7 @@
* @return if this user is a managed profile of another user.
*/
public boolean isManagedProfile(@NonNull ComponentName admin) {
+ throwIfParentInstance("isManagedProfile");
try {
return mService.isManagedProfile(admin);
} catch (RemoteException re) {
@@ -5721,6 +5823,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public String getWifiMacAddress(@NonNull ComponentName admin) {
+ throwIfParentInstance("getWifiMacAddress");
try {
return mService.getWifiMacAddress(admin);
} catch (RemoteException re) {
@@ -5737,6 +5840,7 @@
* @see TelephonyManager#CALL_STATE_IDLE
*/
public void reboot(@NonNull ComponentName admin) {
+ throwIfParentInstance("reboot");
try {
mService.reboot(admin);
} catch (RemoteException re) {
@@ -5763,6 +5867,7 @@
*/
public void setShortSupportMessage(@NonNull ComponentName admin,
@Nullable CharSequence message) {
+ throwIfParentInstance("setShortSupportMessage");
if (mService != null) {
try {
mService.setShortSupportMessage(admin, message);
@@ -5781,6 +5886,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public CharSequence getShortSupportMessage(@NonNull ComponentName admin) {
+ throwIfParentInstance("getShortSupportMessage");
if (mService != null) {
try {
return mService.getShortSupportMessage(admin);
@@ -5807,6 +5913,7 @@
*/
public void setLongSupportMessage(@NonNull ComponentName admin,
@Nullable CharSequence message) {
+ throwIfParentInstance("setLongSupportMessage");
if (mService != null) {
try {
mService.setLongSupportMessage(admin, message);
@@ -5825,6 +5932,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public CharSequence getLongSupportMessage(@NonNull ComponentName admin) {
+ throwIfParentInstance("getLongSupportMessage");
if (mService != null) {
try {
return mService.getLongSupportMessage(admin);
@@ -5922,6 +6030,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
+ throwIfParentInstance("getParentProfileInstance");
try {
if (!mService.isManagedProfile(admin)) {
throw new SecurityException("The current user does not have a parent profile.");
@@ -5948,6 +6057,7 @@
* @see #retrieveSecurityLogs
*/
public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setSecurityLoggingEnabled");
try {
mService.setSecurityLoggingEnabled(admin, enabled);
} catch (RemoteException re) {
@@ -5966,6 +6076,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public boolean isSecurityLoggingEnabled(@NonNull ComponentName admin) {
+ throwIfParentInstance("isSecurityLoggingEnabled");
try {
return mService.isSecurityLoggingEnabled(admin);
} catch (RemoteException re) {
@@ -5989,6 +6100,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {
+ throwIfParentInstance("retrieveSecurityLogs");
try {
ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin);
if (list != null) {
@@ -6034,6 +6146,7 @@
* @throws SecurityException if {@code admin} is not a device owner.
*/
public List<SecurityEvent> retrievePreRebootSecurityLogs(@NonNull ComponentName admin) {
+ throwIfParentInstance("retrievePreRebootSecurityLogs");
try {
ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin);
return list.getList();
@@ -6055,6 +6168,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public void setOrganizationColor(@NonNull ComponentName admin, int color) {
+ throwIfParentInstance("setOrganizationColor");
try {
// always enforce alpha channel to have 100% opacity
color |= 0xFF000000;
@@ -6094,6 +6208,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public @ColorInt int getOrganizationColor(@NonNull ComponentName admin) {
+ throwIfParentInstance("getOrganizationColor");
try {
return mService.getOrganizationColor(admin);
} catch (RemoteException re) {
@@ -6129,6 +6244,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
+ throwIfParentInstance("setOrganizationName");
try {
mService.setOrganizationName(admin, title);
} catch (RemoteException re) {
@@ -6145,6 +6261,7 @@
* @throws SecurityException if {@code admin} is not a profile owner.
*/
public CharSequence getOrganizationName(@NonNull ComponentName admin) {
+ throwIfParentInstance("getOrganizationName");
try {
return mService.getOrganizationName(admin);
} catch (RemoteException re) {
@@ -6176,6 +6293,7 @@
@SystemApi
@UserProvisioningState
public int getUserProvisioningState() {
+ throwIfParentInstance("getUserProvisioningState");
if (mService != null) {
try {
return mService.getUserProvisioningState();
@@ -6222,6 +6340,7 @@
* @param ids A set of opaque affiliation ids.
*/
public void setAffiliationIds(@NonNull ComponentName admin, Set<String> ids) {
+ throwIfParentInstance("setAffiliationIds");
try {
mService.setAffiliationIds(admin, new ArrayList<String>(ids));
} catch (RemoteException e) {
@@ -6237,6 +6356,7 @@
* @return whether this user/profile is affiliated with the device.
*/
public boolean isAffiliatedUser() {
+ throwIfParentInstance("isAffiliatedUser");
try {
return mService != null && mService.isAffiliatedUser();
} catch (RemoteException e) {
@@ -6270,4 +6390,10 @@
throw re.rethrowFromSystemServer();
}
}
+
+ private void throwIfParentInstance(String functionName) {
+ if (mParentInstance) {
+ throw new SecurityException(functionName + " cannot be called on the parent instance");
+ }
+ }
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index aa1e372..4108f6d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1210,7 +1210,7 @@
// For those APKs we only care about extracting signer certificates, and don't care
// about verifying integrity.
boolean signatureSchemeRollbackProtectionsEnforced =
- (parseFlags & PARSE_IS_SYSTEM) == 0;
+ (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
jarFile = new StrictJarFile(
apkPath,
!verified, // whether to verify JAR signature
@@ -1239,7 +1239,7 @@
toVerify.add(manifestEntry);
// If we're parsing an untrusted package, verify all contents
- if ((parseFlags & PARSE_IS_SYSTEM) == 0) {
+ if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
final Iterator<ZipEntry> i = jarFile.iterator();
while (i.hasNext()) {
final ZipEntry entry = i.next();
@@ -1679,7 +1679,6 @@
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
- final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
mParseInstrumentationArgs = null;
mParseActivityArgs = null;
mParseServiceArgs = null;
@@ -1769,8 +1768,6 @@
return null;
}
} else if (tagName.equals(TAG_OVERLAY)) {
- pkg.mTrustedOverlay = trustedOverlay;
-
sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestResourceOverlay);
pkg.mOverlayTarget = sa.getString(
@@ -2924,12 +2921,14 @@
ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
}
- if (sa.getBoolean(R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
- false) && (flags & PARSE_IS_SYSTEM) != 0) {
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
+ false)) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
}
- if (sa.getBoolean(R.styleable.AndroidManifestApplication_directBootAware, false)
- && (flags & PARSE_IS_SYSTEM) != 0) {
+ if (sa.getBoolean(
+ R.styleable.AndroidManifestApplication_directBootAware,
+ false)) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
}
@@ -3554,7 +3553,7 @@
a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestActivity_directBootAware,
- owner.applicationInfo.isDirectBootAware());
+ false);
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3572,7 +3571,7 @@
a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestActivity_directBootAware,
- owner.applicationInfo.isDirectBootAware());
+ false);
}
if (a.info.directBootAware) {
@@ -3985,7 +3984,7 @@
p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestProvider_directBootAware,
- owner.applicationInfo.isDirectBootAware());
+ false);
if (p.info.directBootAware) {
owner.applicationInfo.privateFlags |=
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
@@ -4277,7 +4276,7 @@
s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
R.styleable.AndroidManifestService_directBootAware,
- owner.applicationInfo.isDirectBootAware());
+ false);
if (s.info.directBootAware) {
owner.applicationInfo.privateFlags |=
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 4756b372..271ec79 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -517,7 +517,8 @@
if (mService != null) try {
mEnrollmentCallback = callback;
- mService.enroll(mToken, token, userId, mServiceReceiver, flags);
+ mService.enroll(mToken, token, userId, mServiceReceiver, flags,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in enroll: ", e);
if (callback != null) {
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
index 9c13523..f40f8a3 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
@@ -35,4 +35,6 @@
int closeHal();
void init(IFingerprintDaemonCallback callback);
int postEnroll();
+ int enumerate();
+ int cancelEnumeration();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 43d5577..d7915e3 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -35,7 +35,7 @@
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver,
- int flags);
+ int flags, String opPackageName);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5d008e3..9070ad9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1131,7 +1131,8 @@
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
*
- * @deprecated Deprecated in favor of the cleaner {@link #unregisterNetworkCallback} API.
+ * @deprecated Deprecated in favor of the cleaner
+ * {@link #unregisterNetworkCallback(NetworkCallback)} API.
* In {@link VERSION_CODES#M}, and above, this method is unsupported and will
* throw {@code UnsupportedOperationException} if called.
*/
@@ -2811,7 +2812,7 @@
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback} or the calling application exits.
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
@@ -2848,7 +2849,7 @@
* This function behaves identically to the non-timedout version, but if a suitable
* network is not found within the given time (in milliseconds) the
* {@link NetworkCallback#unavailable} callback is called. The request must
- * still be released normally by calling {@link unregisterNetworkCallback}.
+ * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -2956,7 +2957,8 @@
/**
* Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)}
* <p>
- * This method has the same behavior as {@link #unregisterNetworkCallback} with respect to
+ * This method has the same behavior as
+ * {@link #unregisterNetworkCallback(android.app.PendingIntent)} with respect to
* releasing network resources and disconnecting.
*
* @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the
@@ -2982,7 +2984,7 @@
/**
* Registers to receive notifications about all networks which satisfy the given
* {@link NetworkRequest}. The callbacks will continue to be called until
- * either the application exits or {@link #unregisterNetworkCallback} is called
+ * either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
*
@@ -3035,9 +3037,9 @@
}
/**
- * Registers to receive notifications about whichever network currently satisfies the
- * system default {@link NetworkRequest}. The callbacks will continue to be called until
- * either the application exits or {@link #unregisterNetworkCallback} is called
+ * Registers to receive notifications about changes in the system default network. The callbacks
+ * will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
*
@@ -3060,8 +3062,9 @@
* is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
* network connection for updated bandwidth information. The caller will be notified via
* {@link ConnectivityManager.NetworkCallback} if there is an update. Notice that this
- * method assumes that the caller has previously called {@link #registerNetworkCallback} to
- * listen for network changes.
+ * method assumes that the caller has previously called
+ * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} to listen for network
+ * changes.
*
* @param network {@link Network} specifying which network you're interested.
* @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
@@ -3076,8 +3079,9 @@
/**
* Unregisters callbacks about and possibly releases networks originating from
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and {@link #registerNetworkCallback}
- * calls. If the given {@code NetworkCallback} had previously been used with
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and
+ * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls.
+ * If the given {@code NetworkCallback} had previously been used with
* {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
* will be disconnected.
*
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
new file mode 100644
index 0000000..200b816
--- /dev/null
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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 android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class DnsEvent extends IpConnectivityEvent implements Parcelable {
+ public final int netId;
+
+ // The event type is currently only 1 or 2, so we store it as a byte.
+ public final byte[] eventTypes;
+ // Current getaddrinfo codes go from 1 to EAI_MAX = 15. gethostbyname returns errno, but there
+ // are fewer than 255 errno values. So we store the result code in a byte as well.
+ public final byte[] returnCodes;
+ // The latency is an integer because a) short arrays aren't parcelable and b) a short can only
+ // store a maximum latency of 32757 or 65535 ms, which is too short for pathologically slow
+ // queries.
+ public final int[] latenciesMs;
+
+ private DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
+ this.netId = netId;
+ this.eventTypes = eventTypes;
+ this.returnCodes = returnCodes;
+ this.latenciesMs = latenciesMs;
+ }
+
+ private DnsEvent(Parcel in) {
+ netId = in.readInt();
+ eventTypes = in.createByteArray();
+ returnCodes = in.createByteArray();
+ latenciesMs = in.createIntArray();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(netId);
+ out.writeByteArray(eventTypes);
+ out.writeByteArray(returnCodes);
+ out.writeIntArray(latenciesMs);
+ }
+
+ public static final Parcelable.Creator<DnsEvent> CREATOR = new Parcelable.Creator<DnsEvent>() {
+ @Override
+ public DnsEvent createFromParcel(Parcel in) {
+ return new DnsEvent(in);
+ }
+
+ @Override
+ public DnsEvent[] newArray(int size) {
+ return new DnsEvent[size];
+ }
+ };
+
+ public static void logEvent(
+ int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
+ IpConnectivityEvent.logEvent(IPCE_DNS_LOOKUPS,
+ new DnsEvent(netId, eventTypes, returnCodes, latenciesMs));
+ }
+}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index 59c1cfe..f0a3c90 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -24,31 +24,39 @@
* {@hide}
*/
public class IpConnectivityEvent implements Parcelable {
- // IPRM = IpReachabilityMonitor
- // DHCP = DhcpClient
+ public static final String TAG = "IpConnectivityEvent";
+
+ // IPRM = IpReachabilityMonitor
+ // DHCP = DhcpClient
// NETMON = NetworkMonitorEvent
// CONSRV = ConnectivityServiceEvent
- // IPMGR = IpManager
- public static final String TAG = "IpConnectivityEvent";
- public static final int IPCE_IPRM_BASE = 0*1024;
- public static final int IPCE_DHCP_BASE = 1*1024;
- public static final int IPCE_NETMON_BASE = 2*1024;
- public static final int IPCE_CONSRV_BASE = 3*1024;
- public static final int IPCE_IPMGR_BASE = 4*1024;
+ // IPMGR = IpManager
+ public static final int IPCE_IPRM_BASE = 0 * 1024;
+ public static final int IPCE_DHCP_BASE = 1 * 1024;
+ public static final int IPCE_NETMON_BASE = 2 * 1024;
+ public static final int IPCE_CONSRV_BASE = 3 * 1024;
+ public static final int IPCE_IPMGR_BASE = 4 * 1024;
+ public static final int IPCE_DNS_BASE = 5 * 1024;
- public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
- public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
- public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
- public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
- public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
- public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
- public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3;
- public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
- public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
+ public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
+ public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+ public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
+
+ public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
+ public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
+ public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
+ public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3;
+
+ public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
+ public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
+
public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
- public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0;
- public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1;
- public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2;
+
+ public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0;
+ public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1;
+ public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2;
+
+ public static final int IPCE_DNS_LOOKUPS = IPCE_DNS_BASE + 0;
private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 67d3959..55b0d2a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.content.pm.UserInfo;
+import android.content.IntentSender;
import android.content.RestrictionEntry;
import android.graphics.Bitmap;
import android.os.ParcelFileDescriptor;
@@ -70,6 +71,7 @@
boolean markGuestForDeletion(int userHandle);
void setQuietModeEnabled(int userHandle, boolean enableQuietMode);
boolean isQuietModeEnabled(int userHandle);
+ boolean trySetQuietModeDisabled(int userHandle, in IntentSender target);
void setSeedAccountData(int userHandle, in String accountName,
in String accountType, in PersistableBundle accountOptions, boolean persist);
String getSeedAccountName();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d5b3b35..086a977 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -29,6 +29,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -1691,6 +1692,23 @@
}
/**
+ * Tries disabling quiet mode for a given user. If the user is still locked, we unlock the user
+ * first by showing the confirm credentials screen and disable quiet mode upon successful
+ * unlocking. If the user is already unlocked, we call through to {@link #setQuietModeEnabled}
+ * directly.
+ *
+ * @return true if the quiet mode was disabled immediately
+ * @hide
+ */
+ public boolean trySetQuietModeDisabled(@UserIdInt int userHandle, IntentSender target) {
+ try {
+ return mService.trySetQuietModeDisabled(userHandle, target);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* If the target user is a managed profile of the calling user or the caller
* is itself a managed profile, then this returns a badged copy of the given
* icon to be able to distinguish it from the original icon. For badging an
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index 88ac271..36a81db 100644
--- a/core/java/android/view/IDockedStackListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -44,6 +44,15 @@
void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
/**
+ * Called when window manager decides to adjust the divider for IME. Like the minimized state,
+ * the divider should make itself not interactable and shrink a bit, but in a different way.s
+ *
+ * @param minimized Whether the stacks are currently adjusted for the IME
+ * @param animDuration The duration of the animation for changing the adjusted state.
+ */
+ void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration);
+
+ /**
* Called when window manager repositioned the docked stack after a screen rotation change.
*/
void onDockSideChanged(int newDockSide);
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 27588e9..d24cefe 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -107,9 +107,8 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
- UserManager.get(this).setQuietModeEnabled(mUserId, false);
-
- if (mTarget != null) {
+ if (UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget)
+ && mTarget != null) {
try {
startIntentSenderForResult(mTarget, -1, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 9e5c238..36e21b9 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -63,7 +63,7 @@
void toggleSplitScreen();
void preloadRecentApps();
void cancelPreloadRecentApps();
- void showScreenPinningRequest();
+ void showScreenPinningRequest(int taskId);
void toggleKeyboardShortcutsMenu(int deviceId);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 22a81d4..d681246 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -752,17 +752,32 @@
getPremulBitmapCreateFlags(isMutable));
}
-static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
- SkBitmap src;
- reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
+static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
SkBitmap result;
AshmemPixelAllocator allocator(env);
- if (!src.copyTo(&result, &allocator)) {
+ if (!src.copyTo(&result, dstCT, &allocator)) {
return NULL;
}
Bitmap* bitmap = allocator.getStorageObjAndReset();
bitmap->peekAtPixelRef()->setImmutable();
+ return bitmap;
+}
+
+static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
+ SkBitmap src;
+ reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
+ SkColorType dstCT = src.colorType();
+ Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
+ jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+ return ret;
+}
+
+static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
+ SkBitmap src;
+ reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
+ SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
+ Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
return ret;
}
@@ -1355,6 +1370,8 @@
(void*)Bitmap_copy },
{ "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
(void*)Bitmap_copyAshmem },
+ { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_copyAshmemConfig },
{ "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
{ "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
{ "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index f46f45c..898cf77 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -815,10 +815,15 @@
}
if (prevCp != kStartOfString &&
- ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF)) &&
- !MinikinUtils::hasVariationSelector(typeface, prevCp, cp)) {
- // No font has a glyph for the code point and variation selector pair.
- return false;
+ ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF))) {
+ bool hasVS = MinikinUtils::hasVariationSelector(typeface, prevCp, cp);
+ if (!hasVS) {
+ // No font has a glyph for the code point and variation selector pair.
+ return false;
+ } else if (nChars == 1 && i + 1 == str.size()) {
+ // The string is just a codepoint and a VS, we have an authoritative answer
+ return true;
+ }
}
nChars++;
prevCp = cp;
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml
index 117774a..575404d 100644
--- a/core/res/res/anim/input_method_exit.xml
+++ b/core/res/res/anim/input_method_exit.xml
@@ -17,10 +17,10 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <translate android:fromYDelta="0" android:toYDelta="10%"
- android:interpolator="@interpolator/accelerate_quint"
- android:duration="@android:integer/config_shortAnimTime"/>
+ <translate android:fromYDelta="0" android:toYDelta="8%"
+ android:interpolator="@interpolator/fast_out_linear_in"
+ android:duration="150"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="@android:integer/config_shortAnimTime"/>
+ android:interpolator="@interpolator/fast_out_linear_in"
+ android:duration="150"/>
</set>
diff --git a/core/res/res/layout/floating_popup_overflow_button.xml b/core/res/res/layout/floating_popup_overflow_button.xml
index 7053f3e..12e2000 100644
--- a/core/res/res/layout/floating_popup_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_overflow_button.xml
@@ -24,5 +24,5 @@
android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding"
android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding"
android:scaleType="centerInside"
- android:background="?attr/selectableItemBackgroundBorderless"
+ android:background="?attr/actionBarItemBackground"
android:tint="?attr/floatingToolbarForegroundColor" />
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index b652127..65a5015 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -16,8 +16,8 @@
-->
<ImageView android:id="@+id/right_icon" xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/notification_large_icon_width"
- android:layout_height="@dimen/notification_large_icon_width"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="36dp"
android:layout_gravity="top|end"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9178305..8200df8 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -162,9 +162,9 @@
<dimen name="notification_min_height">92dp</dimen>
<!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_width">40dp</dimen>
+ <dimen name="notification_large_icon_width">64dp</dimen>
<!-- The width of the big icons in notifications. -->
- <dimen name="notification_large_icon_height">40dp</dimen>
+ <dimen name="notification_large_icon_height">64dp</dimen>
<!-- The minimum width of the app name in the header if it shrinks -->
<dimen name="notification_header_shrink_min_width">72dp</dimen>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 169ef0b..ac2a88a 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -25,14 +25,14 @@
import android.util.DisplayMetrics;
import android.util.Log;
+import libcore.util.NativeAllocationRegistry;
+
import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
-import libcore.util.NativeAllocationRegistry;
-
public final class Bitmap implements Parcelable {
private static final String TAG = "Bitmap";
@@ -614,6 +614,22 @@
}
/**
+ * Creates a new immutable bitmap backed by ashmem which can efficiently
+ * be passed between processes.
+ *
+ * @hide
+ */
+ public Bitmap createAshmemBitmap(Config config) {
+ checkRecycled("Can't copy a recycled bitmap");
+ Bitmap b = nativeCopyAshmemConfig(mNativePtr, config.nativeInt);
+ if (b != null) {
+ b.setPremultiplied(mRequestPremultiplied);
+ b.mDensity = mDensity;
+ }
+ return b;
+ }
+
+ /**
* Creates a new bitmap, scaled from an existing bitmap, when possible. If the
* specified width and height are the same as the current width and height of
* the source bitmap, the source bitmap is returned and no new bitmap is
@@ -1675,6 +1691,7 @@
private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
boolean isMutable);
private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
+ private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
private static native long nativeGetNativeFinalizer();
private static native boolean nativeRecycle(long nativeBitmap);
private static native void nativeReconfigure(long nativeBitmap, int width, int height,
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 715c875..6913f43 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -34,7 +34,9 @@
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Timers.h>
-#include <utils/Trace.h>
+#ifdef __ANDROID__
+#include <cutils/trace.h>
+#endif
#include <assert.h>
#include <dirent.h>
@@ -52,6 +54,14 @@
_rc; })
#endif
+#ifdef __ANDROID__
+#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
+#define MY_TRACE_END() ATRACE_END()
+#else
+#define MY_TRACE_BEGIN(x)
+#define MY_TRACE_END()
+#endif
+
using namespace android;
static const bool kIsDebug = false;
@@ -613,7 +623,7 @@
ResTable* sharedRes = NULL;
bool shared = true;
bool onlyEmptyResources = true;
- ATRACE_NAME(ap.path.string());
+ MY_TRACE_BEGIN(ap.path.string());
Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -693,6 +703,8 @@
if (idmap != NULL) {
delete idmap;
}
+ MY_TRACE_END();
+
return onlyEmptyResources;
}
@@ -740,7 +752,6 @@
void AssetManager::updateResourceParamsLocked() const
{
- ATRACE_CALL();
ResTable* res = mResources;
if (!res) {
return;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 15cb684..1ccc59a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
-#include <algorithm>
#include <limits>
#include <memory>
#include <type_traits>
@@ -5811,10 +5810,6 @@
return NULL;
}
-static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
- return a.compare(b) < 0;
-}
-
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size();
@@ -5845,11 +5840,17 @@
ResTable_config cfg;
memset(&cfg, 0, sizeof(ResTable_config));
cfg.copyFromDtoH(config->config);
-
- auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
- compareResTableConfig);
- if (iter == configs->end() || iter->compare(cfg) != 0) {
- configs->insertAt(cfg, std::distance(configs->begin(), iter));
+ // only insert unique
+ const size_t N = configs->size();
+ size_t n;
+ for (n = 0; n < N; n++) {
+ if (0 == (*configs)[n].compare(cfg)) {
+ break;
+ }
+ }
+ // if we didn't find it
+ if (n == N) {
+ configs->add(cfg);
}
}
}
@@ -5857,10 +5858,6 @@
}
}
-static bool compareString8AndCString(const String8& str, const char* cStr) {
- return strcmp(str.string(), cStr) < 0;
-}
-
void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
Vector<ResTable_config> configs;
@@ -5875,11 +5872,15 @@
char locale[RESTABLE_MAX_LOCALE_LEN];
for (size_t i=0; i<I; i++) {
configs[i].getBcp47Locale(locale);
-
- auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
- compareString8AndCString);
- if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
- locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
+ const size_t J = locales->size();
+ size_t j;
+ for (j=0; j<J; j++) {
+ if (0 == strcmp(locale, (*locales)[j].string())) {
+ break;
+ }
+ }
+ if (j == J) {
+ locales->add(String8(locale));
}
}
}
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index b8b4625..7cd7fb5 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -39,20 +39,8 @@
*/
#include "data/basic/basic_arsc.h"
-/**
- * Include a binary library resource table.
- *
- * Package: com.android.test.basic
- */
#include "data/lib/lib_arsc.h"
-/**
- * Include a system resource table.
- *
- * Package: android
- */
-#include "data/system/system_arsc.h"
-
TEST(ResTableTest, shouldLoadSuccessfully) {
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -336,25 +324,4 @@
ASSERT_EQ(uint32_t(600), val.data);
}
-TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
- ResTable table;
- ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
- ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
-
- ResTable_config configSv;
- memset(&configSv, 0, sizeof(configSv));
- configSv.language[0] = 's';
- configSv.language[1] = 'v';
-
- Vector<ResTable_config> configs;
- table.getConfigurations(&configs);
-
- EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
-
- Vector<String8> locales;
- table.getLocales(&locales);
-
- EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
-}
-
} // namespace
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ff9be16..ac80d88 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -21,7 +21,7 @@
enum { MAY_NOT_BE_BAG = false };
static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
- return a.compare(b) == 0;
+ return memcmp(&a, &b, sizeof(a)) == 0;
}
static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 6a31fb8..27f25fe 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -33,12 +33,6 @@
};
}
-namespace integer {
- enum {
- number = 0x01030000, // sv
- };
-}
-
} // namespace R
} // namespace android
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
deleted file mode 100644
index b97bdb6..0000000
--- a/libs/androidfw/tests/data/system/res/values-sv/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<resources>
- <public type="integer" name="number" id="0x01030000" />
- <integer name="number">1</integer>
-</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index b0dab6b..215ecae 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
unsigned char system_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,33 +25,26 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
- 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
- 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
- 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
- 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
+ 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
- 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
- 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+ 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -62,27 +55,15 @@
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
- 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
- 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
- 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
- 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
- 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
+ 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
};
-unsigned int system_arsc_len = 1016;
+unsigned int system_arsc_len = 792;
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 691cfa0..1c6f48e 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -219,22 +219,24 @@
int fillType = 0; /* non-zero or kWinding_FillType in Skia */
};
FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
+ ~FullPathProperties() {
+ SkSafeUnref(fillGradient);
+ SkSafeUnref(strokeGradient);
+ }
void syncProperties(const FullPathProperties& prop) {
mPrimitiveFields = prop.mPrimitiveFields;
mTrimDirty = true;
- fillGradient.reset(prop.fillGradient);
- strokeGradient.reset(prop.strokeGradient);
+ UPDATE_SKPROP(fillGradient, prop.fillGradient);
+ UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
onPropertyChanged();
}
void setFillGradient(SkShader* gradient) {
- if(fillGradient != gradient){
- fillGradient.reset(gradient);
+ if(UPDATE_SKPROP(fillGradient, gradient)) {
onPropertyChanged();
}
}
void setStrokeGradient(SkShader* gradient) {
- if(strokeGradient != gradient){
- strokeGradient.reset(gradient);
+ if(UPDATE_SKPROP(strokeGradient, gradient)) {
onPropertyChanged();
}
}
@@ -346,8 +348,8 @@
count,
};
PrimitiveFields mPrimitiveFields;
- SkAutoTUnref<SkShader> fillGradient;
- SkAutoTUnref<SkShader> strokeGradient;
+ SkShader* fillGradient = nullptr;
+ SkShader* strokeGradient = nullptr;
};
// Called from UI thread
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 7c6adad..2cd9872 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -27,6 +27,7 @@
import android.media.MediaDescription;
import android.media.session.MediaController;
import android.media.session.MediaSession;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -475,14 +476,8 @@
// the service will be told when we connect.
if (mState == CONNECT_STATE_CONNECTED) {
try {
- // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise,
- // it will break the action of support library which expects addSubscription will
- // be called when options are null.
- if (options == null) {
- mServiceBinder.addSubscription(parentId, mServiceCallbacks);
- } else {
- mServiceBinder.addSubscriptionWithOptions(parentId, options, mServiceCallbacks);
- }
+ mServiceBinder.addSubscription(parentId, callback.mToken, options,
+ mServiceCallbacks);
} catch (RemoteException ex) {
// Process is crashing. We will disconnect, and upon reconnect we will
// automatically reregister. So nothing to do here.
@@ -497,34 +492,37 @@
throw new IllegalArgumentException("parentId is empty.");
}
- // Remove from our list.
Subscription sub = mSubscriptions.get(parentId);
-
+ if (sub == null) {
+ return;
+ }
// Tell the service if necessary.
- if (mState == CONNECT_STATE_CONNECTED && sub != null) {
- try {
- if (callback == null) {
- mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
- } else {
- final List<SubscriptionCallback> callbacks = sub.getCallbacks();
- final List<Bundle> optionsList = sub.getOptionsList();
- for (int i = callbacks.size() - 1; i >= 0; --i) {
- if (callbacks.get(i) == callback) {
- mServiceBinder.removeSubscriptionWithOptions(
- parentId, optionsList.get(i), mServiceCallbacks);
- callbacks.remove(i);
- optionsList.remove(i);
+ try {
+ if (callback == null) {
+ if (mState == CONNECT_STATE_CONNECTED) {
+ mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
+ }
+ } else {
+ final List<SubscriptionCallback> callbacks = sub.getCallbacks();
+ final List<Bundle> optionsList = sub.getOptionsList();
+ for (int i = callbacks.size() - 1; i >= 0; --i) {
+ if (callbacks.get(i) == callback) {
+ if (mState == CONNECT_STATE_CONNECTED) {
+ mServiceBinder.removeSubscription(
+ parentId, callback.mToken, mServiceCallbacks);
}
+ callbacks.remove(i);
+ optionsList.remove(i);
}
}
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
}
+ } catch (RemoteException ex) {
+ // Process is crashing. We will disconnect, and upon reconnect we will
+ // automatically reregister. So nothing to do here.
+ Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
}
- if (sub != null && (sub.isEmpty() || callback == null)) {
+ if (sub.isEmpty() || callback == null) {
mSubscriptions.remove(parentId);
}
}
@@ -579,17 +577,12 @@
for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
String id = subscriptionEntry.getKey();
Subscription sub = subscriptionEntry.getValue();
- for (Bundle options : sub.getOptionsList()) {
+ List<SubscriptionCallback> callbackList = sub.getCallbacks();
+ List<Bundle> optionsList = sub.getOptionsList();
+ for (int i = 0; i < callbackList.size(); ++i) {
try {
- // NOTE: Do not call addSubscriptionWithOptions when options are null.
- // Otherwise, it will break the action of support library which expects
- // addSubscription will be called when options are null.
- if (options == null) {
- mServiceBinder.addSubscription(id, mServiceCallbacks);
- } else {
- mServiceBinder.addSubscriptionWithOptions(
- id, options, mServiceCallbacks);
- }
+ mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
+ optionsList.get(i), mServiceCallbacks);
} catch (RemoteException ex) {
// Process is crashing. We will disconnect, and upon reconnect we will
// automatically reregister. So nothing to do here.
@@ -859,6 +852,12 @@
* Callbacks for subscription related events.
*/
public static abstract class SubscriptionCallback {
+ Binder mToken;
+
+ public SubscriptionCallback() {
+ mToken = new Binder();
+ }
+
/**
* Called when the list of children is loaded or updated.
*
@@ -1071,12 +1070,7 @@
}
@Override
- public void onLoadChildren(String parentId, ParceledListSlice list) {
- onLoadChildrenWithOptions(parentId, list, null);
- }
-
- @Override
- public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
+ public void onLoadChildren(String parentId, ParceledListSlice list,
final Bundle options) {
MediaBrowser mediaBrowser = mMediaBrowser.get();
if (mediaBrowser != null) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index e134635..21211d7 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -839,9 +839,11 @@
public abstract boolean onTune(Uri channelUri);
/**
- * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific
+ * Tunes to a given channel. Override this method in order to handle domain-specific
* features that are only known between certain TV inputs and their clients.
*
+ * <p>The default implementation calls {@link #onTune(Uri)}.
+ *
* @param channelUri The URI of the channel.
* @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped
* name, i.e. prefixed with a package name you own, so that different developers
@@ -1693,11 +1695,12 @@
public abstract void onTune(Uri channelUri);
/**
- * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific
- * features that are only known between certain TV inputs and their clients.
+ * Called when the application requests to tune to a given channel for TV program recording.
+ * Override this method in order to handle domain-specific features that are only known
+ * between certain TV inputs and their clients.
*
* <p>The application may call this method before starting or after stopping recording, but
- * not during recording.
+ * not during recording. The default implementation calls {@link #onTune(Uri)}.
*
* <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or
* {@link #notifyError(int)} otherwise.
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index 6ca5ac5..eef5a7c 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -14,19 +14,11 @@
* @hide
*/
oneway interface IMediaBrowserService {
-
- // Warning: DO NOT CHANGE the methods signature and order of methods.
- // A change of the order or the method signatures could break the support library.
-
void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
void disconnect(IMediaBrowserServiceCallbacks callbacks);
- void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
- void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
+ void addSubscription(String uri, in IBinder token, in Bundle options,
+ IMediaBrowserServiceCallbacks callbacks);
+ void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
void getMediaItem(String uri, in ResultReceiver cb);
-
- void addSubscriptionWithOptions(String uri, in Bundle options,
- IMediaBrowserServiceCallbacks callbacks);
- void removeSubscriptionWithOptions(String uri, in Bundle options,
- IMediaBrowserServiceCallbacks callbacks);
}
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index e6b0e8c..dadb025 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -13,10 +13,6 @@
* @hide
*/
oneway interface IMediaBrowserServiceCallbacks {
-
- // Warning: DO NOT CHANGE the methods signature and order of methods.
- // A change of the order or the method signatures could break the support library.
-
/**
* Invoked when the connected has been established.
* @param root The root media id for browsing.
@@ -26,6 +22,5 @@
*/
void onConnect(String root, in MediaSession.Token session, in Bundle extras);
void onConnectFailed();
- void onLoadChildren(String mediaId, in ParceledListSlice list);
- void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
+ void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6954045..ddc0e88 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -39,6 +39,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -108,7 +109,7 @@
Bundle rootHints;
IMediaBrowserServiceCallbacks callbacks;
BrowserRoot root;
- HashMap<String, List<Bundle>> subscriptions = new HashMap<>();
+ HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
}
/**
@@ -247,13 +248,7 @@
}
@Override
- public void addSubscription(final String id,
- final IMediaBrowserServiceCallbacks callbacks) {
- addSubscriptionWithOptions(id, null, callbacks);
- }
-
- @Override
- public void addSubscriptionWithOptions(final String id, final Bundle options,
+ public void addSubscription(final String id, final IBinder token, final Bundle options,
final IMediaBrowserServiceCallbacks callbacks) {
mHandler.post(new Runnable() {
@Override
@@ -268,19 +263,13 @@
return;
}
- MediaBrowserService.this.addSubscription(id, connection, options);
+ MediaBrowserService.this.addSubscription(id, connection, token, options);
}
});
}
@Override
- public void removeSubscription(final String id,
- final IMediaBrowserServiceCallbacks callbacks) {
- removeSubscriptionWithOptions(id, null, callbacks);
- }
-
- @Override
- public void removeSubscriptionWithOptions(final String id, final Bundle options,
+ public void removeSubscription(final String id, final IBinder token,
final IMediaBrowserServiceCallbacks callbacks) {
mHandler.post(new Runnable() {
@Override
@@ -293,7 +282,7 @@
+ id);
return;
}
- if (!MediaBrowserService.this.removeSubscription(id, connection, options)) {
+ if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
Log.w(TAG, "removeSubscription called for " + id
+ " which is not subscribed");
}
@@ -519,11 +508,12 @@
public void run() {
for (IBinder binder : mConnections.keySet()) {
ConnectionRecord connection = mConnections.get(binder);
- List<Bundle> optionsList = connection.subscriptions.get(parentId);
- if (optionsList != null) {
- for (Bundle bundle : optionsList) {
- if (MediaBrowserUtils.hasDuplicatedItems(options, bundle)) {
- performLoadChildren(parentId, connection, bundle);
+ List<Pair<IBinder, Bundle>> callbackList =
+ connection.subscriptions.get(parentId);
+ if (callbackList != null) {
+ for (Pair<IBinder, Bundle> callback : callbackList) {
+ if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
+ performLoadChildren(parentId, connection, callback.second);
}
}
}
@@ -553,19 +543,21 @@
/**
* Save the subscription and if it is a new subscription send the results.
*/
- private void addSubscription(String id, ConnectionRecord connection, Bundle options) {
+ private void addSubscription(String id, ConnectionRecord connection, IBinder token,
+ Bundle options) {
// Save the subscription
- List<Bundle> optionsList = connection.subscriptions.get(id);
- if (optionsList == null) {
- optionsList = new ArrayList<>();
+ List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
+ if (callbackList == null) {
+ callbackList = new ArrayList<>();
}
- for (Bundle bundle : optionsList) {
- if (MediaBrowserUtils.areSameOptions(options, bundle)) {
+ for (Pair<IBinder, Bundle> callback : callbackList) {
+ if (token == callback.first
+ && MediaBrowserUtils.areSameOptions(options, callback.second)) {
return;
}
}
- optionsList.add(options);
- connection.subscriptions.put(id, optionsList);
+ callbackList.add(new Pair<>(token, options));
+ connection.subscriptions.put(id, callbackList);
// send the results
performLoadChildren(id, connection, options);
}
@@ -573,21 +565,20 @@
/**
* Remove the subscription.
*/
- private boolean removeSubscription(String id, ConnectionRecord connection, Bundle options) {
- if (options == null) {
+ private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
+ if (token == null) {
return connection.subscriptions.remove(id) != null;
}
boolean removed = false;
- List<Bundle> optionsList = connection.subscriptions.get(id);
- if (optionsList != null) {
- for (Bundle bundle : optionsList) {
- if (MediaBrowserUtils.areSameOptions(options, bundle)) {
+ List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
+ if (callbackList != null) {
+ for (Pair<IBinder, Bundle> callback : callbackList) {
+ if (token == callback.first) {
removed = true;
- optionsList.remove(bundle);
- break;
+ callbackList.remove(callback);
}
}
- if (optionsList.size() == 0) {
+ if (callbackList.size() == 0) {
connection.subscriptions.remove(id);
}
}
@@ -619,14 +610,7 @@
final ParceledListSlice<MediaBrowser.MediaItem> pls =
filteredList == null ? null : new ParceledListSlice<>(filteredList);
try {
- // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise,
- // it will break the action of support library which expects onLoadChildren will
- // be called when options are null.
- if (options == null) {
- connection.callbacks.onLoadChildren(parentId, pls);
- } else {
- connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
- }
+ connection.callbacks.onLoadChildren(parentId, pls, options);
} catch (RemoteException ex) {
// The other side is in the process of crashing.
Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
index 418a3f2..ae23720 100644
--- a/media/jni/android_media_ExifInterface.cpp
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -136,7 +136,8 @@
KeyedVector<String8, String8> map;
- if (image_data.thumbnail.length > 0) {
+ if (image_data.thumbnail.length > 0
+ && image_data.thumbnail.format == ::piex::Image::kJpegCompressed) {
map.add(String8("hasThumbnail"), String8("true"));
map.add(String8("thumbnailOffset"), String8::format("%d", image_data.thumbnail.offset));
map.add(String8("thumbnailLength"), String8::format("%d", image_data.thumbnail.length));
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 39f2a32..d6bf9ad 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -932,8 +932,9 @@
break;
}
- if (image_data.thumbnail.length == 0) {
- // No thumbnail.
+ if (image_data.thumbnail.length == 0
+ || image_data.thumbnail.format == ::piex::Image::kJpegCompressed) {
+ // No thumbnail or non jpeg thumbnail.
break;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 0e27622..2be93b8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -17,6 +17,7 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_CREATE;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -107,8 +108,9 @@
mAdapter.update(data);
// When launched into empty recents, show drawer
- if (mAdapter.isEmpty() && !state.hasLocationChanged() &&
- context instanceof DocumentsActivity) {
+ if (mAdapter.isEmpty() && !state.hasLocationChanged()
+ && state.action != ACTION_CREATE
+ && context instanceof DocumentsActivity) {
((DocumentsActivity) context).setRootsDrawerOpen(true);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index e6217b2..e3eae33 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -90,6 +90,10 @@
*/
private static final class DocumentsTuner extends FragmentTuner {
+ // We use this to keep track of whether a model has been previously loaded or not so we can
+ // open the drawer on empty directories on first launch
+ private boolean mModelPreviousLoaded;
+
public DocumentsTuner(Context context, State state) {
super(context, state);
}
@@ -178,10 +182,12 @@
showDrawer = true;
}
- if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch) {
+ if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch
+ && !mModelPreviousLoaded) {
// This noops on layouts without drawer, so no need to guard.
((BaseActivity) mContext).setRootsDrawerOpen(true);
}
+ mModelPreviousLoaded = true;
}
@Override
diff --git a/packages/SettingsLib/res/drawable/notification_auto_importance.xml b/packages/SettingsLib/res/drawable/notification_auto_importance.xml
new file mode 100644
index 0000000..a63e911b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/notification_auto_importance.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2016 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M11.2,13.6l1.6,0l-0.8,-2.6z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22.5,9.6L15,9l-3,-7L9,9L1.5,9.6l5.7,5L5.5,22l6.5,-3.9l6.5,3.9l-1.7,-7.4L22.5,9.6zM13.6,16l-0.5,-1.4h-2.3L10.4,16H9l2.3,-6.4h1.4L15,16H13.6z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 062ae35..e1424f0 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -32,7 +32,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="14dp"
+ android:paddingTop="15dp"
android:paddingEnd="8dp"
android:id="@+id/notification_guts_header"
android:orientation="horizontal"
@@ -99,6 +99,7 @@
android:clickable="false"
android:focusable="false"
android:paddingEnd="8dp"
+ android:paddingTop="4dp"
android:visibility="gone">
<TextView
android:id="@+id/title"
@@ -123,21 +124,20 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
android:paddingTop="8dp" >
<ImageView
- android:id="@+id/low_importance"
- android:src="@*android:drawable/ic_notification_block"
+ android:id="@+id/auto_importance"
+ android:src="@drawable/notification_auto_importance"
android:layout_gravity="center_vertical|start"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:tint="@color/notification_guts_icon_tint"/>
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
<SeekBar
android:id="@+id/seekbar"
android:layout_marginStart="56dp"
- android:layout_marginEnd="56dp"
+ android:layout_marginEnd="32dp"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="48dp"
@@ -149,14 +149,6 @@
style="@android:style/Widget.Material.SeekBar.Discrete"
android:tickMarkTint="@android:color/black" />
- <ImageView
- android:id="@+id/max_importance"
- android:src="@*android:drawable/ic_notification_alert"
- android:layout_gravity="center_vertical|end"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:tint="@color/notification_guts_icon_tint" />
-
</FrameLayout>
</LinearLayout>
<!-- buttons -->
diff --git a/packages/SystemUI/res/layout/power_notification_controls_settings.xml b/packages/SystemUI/res/layout/power_notification_controls_settings.xml
new file mode 100644
index 0000000..83c8a51
--- /dev/null
+++ b/packages/SystemUI/res/layout/power_notification_controls_settings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/switch_bar" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:text="@string/power_notification_controls_description"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 2df57bf..5ee242d 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -43,7 +43,8 @@
android:singleLine="true"
android:maxLines="1"
android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ android:fadingEdge="horizontal"
+ android:forceHasOverlappingRendering="false" />
<com.android.systemui.recents.views.FixedSizeImageView
android:id="@+id/move_task"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d26fb06..c75741c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -108,6 +108,7 @@
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
<color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
+ <color name="notification_guts_disabled_slider_color">@*android:color/material_grey_300</color>
<color name="notification_guts_secondary_slider_color">#858383</color>
<color name="notification_guts_icon_tint">#8a000000</color>
<color name="notification_guts_disabled_icon_tint">#4d000000</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a4d7a18..37b00bb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1225,38 +1225,69 @@
<string name="do_not_silence_block">Don\'t silence or block</string>
<!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
- <string name="tuner_full_importance_settings">Show full importance settings</string>
+ <string name="tuner_full_importance_settings">Power notification controls</string>
+ <string name="tuner_full_importance_settings_on">On</string>
+ <string name="tuner_full_importance_settings_off">Off</string>
+ <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications.
+ \n\n<b>Level 5</b>
+ \n- Show at the top of the notification list
+ \n- Allow full screen interruption
+ \n- Always peek
+ \n\n<b>Level 4</b>
+ \n- Prevent full screen interruption
+ \n- Always peek
+ \n\n<b>Level 3</b>
+ \n- Prevent full screen interruption
+ \n- Never peek
+ \n\n<b>Level 2</b>
+ \n- Prevent full screen interruption
+ \n- Never peek
+ \n- Never make sound and vibration
+ \n\n<b>Level 1</b>
+ \n- Prevent full screen interruption
+ \n- Never peek
+ \n- Never make sound or vibrate
+ \n- Hide from lock screen and status bar
+ \n- Show at the bottom of the notification list
+ \n\n<b>Level 0</b>
+ \n- Block all notifications from the app
+ </string>
+ <!-- Notification importance title, user unspecified status-->
+ <string name="user_unspecified_importance">Importance: Automatic</string>
<!-- Notification importance title, blocked status-->
- <string name="blocked_importance">Blocked</string>
+ <string name="blocked_importance">Importance: Level 0</string>
<!-- Notification importance title, min status-->
- <string name="min_importance">Min importance</string>
+ <string name="min_importance">Importance: Level 1</string>
<!-- Notification importance title, low status-->
- <string name="low_importance">Low importance</string>
+ <string name="low_importance">Importance: Level 2</string>
<!-- Notification importance title, normal status-->
- <string name="default_importance">Normal importance</string>
+ <string name="default_importance">Importance: Level 3</string>
<!-- Notification importance title, high status-->
- <string name="high_importance">High importance</string>
+ <string name="high_importance">Importance: Level 4</string>
<!-- Notification importance title, max status-->
- <string name="max_importance">Urgent importance</string>
+ <string name="max_importance">Importance: Level 5</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
- <string name="notification_importance_blocked">Never show these notifications</string>
+ <string name="notification_importance_user_unspecified">App determines importance for each notification.</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
+ <string name="notification_importance_blocked">Never show notifications from this app.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: min importance level description -->
- <string name="notification_importance_min">Silently show at the bottom of the notification list</string>
+ <string name="notification_importance_min">No full screen interruption, peeking, sound, or vibration. Hide from lock screen and status bar.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
- <string name="notification_importance_low">Silently show these notifications</string>
+ <string name="notification_importance_low">No full screen interruption, peeking, sound, or vibration.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
- <string name="notification_importance_default">Allow these notification to make sounds</string>
+ <string name="notification_importance_default">No full screen interruption or peeking.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
- <string name="notification_importance_high">Peek onto the screen and allow sound and allow sound</string>
+ <string name="notification_importance_high">Always peek. No full screen interruption.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
- <string name="notification_importance_max">Show at the top of the notifications list, peek onto the screen and allow sound</string>
+ <string name="notification_importance_max">Always peek, and allow full screen interruption.</string>
<!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
<string name="notification_more_settings">More settings</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0730083..aeb484f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -33,6 +33,7 @@
<item name="android:windowBackground">@color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
+ <item name="android:windowDisablePreview">true</item>
</style>
<!-- Performance optimized Recents theme (no wallpaper) -->
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
new file mode 100644
index 0000000..3c872fa
--- /dev/null
+++ b/packages/SystemUI/res/xml/other_settings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/other">
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="overview_nav_bar_gesture"
+ android:title="@string/overview_nav_bar_gesture"
+ android:summary="@string/overview_nav_bar_gesture_desc" />
+
+ <!-- importance -->
+ <Preference
+ android:key="power_notification_controls"
+ android:title="@string/tuner_full_importance_settings"
+ android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 1af9075..116bc69 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -135,21 +135,10 @@
android:fragment="com.android.systemui.tuner.NavBarTuner" />
-->
- <PreferenceScreen
- android:key="other"
- android:title="@string/other" >
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_nav_bar_gesture"
- android:title="@string/overview_nav_bar_gesture"
- android:summary="@string/overview_nav_bar_gesture_desc" />
-
- <!-- importance -->
- <com.android.systemui.tuner.TunerSwitch
- android:key="show_importance_slider"
- android:title="@string/tuner_full_importance_settings" />
-
- </PreferenceScreen>
+ <Preference
+ android:key="other"
+ android:title="@string/other"
+ android:fragment="com.android.systemui.tuner.OtherPrefs" />
<!-- Warning, this goes last. -->
<Preference
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1abd073..4d8e33d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1215,7 +1215,6 @@
private void lockProfile(int userId) {
mTrustManager.setDeviceLockedForUser(userId, true);
- notifyLockedProfile(userId);
}
private boolean shouldWaitForProvisioning() {
@@ -1546,13 +1545,6 @@
}
}
- private void notifyLockedProfile(@UserIdInt int userId) {
- try {
- ActivityManagerNative.getDefault().notifyLockedProfile(userId);
- } catch (RemoteException e) {
- }
- }
-
/**
* Handle message sent by {@link #showLocked}.
* @see #SHOW
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index 9a00d95..1240e05 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -27,7 +27,7 @@
void registerNonSystemUserCallbacks(IBinder nonSystemUserCallbacks, int userId);
void updateRecentsVisibility(boolean visible);
- void startScreenPinning();
+ void startScreenPinning(int taskId);
void sendRecentsDrawnEvent();
void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
void sendLaunchRecentsEvent();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index b2d7b48..a227e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -598,13 +598,13 @@
public final void onBusEvent(final ScreenPinningRequestEvent event) {
int processUser = sSystemServicesProxy.getProcessUser();
if (sSystemServicesProxy.isSystemUser(processUser)) {
- mImpl.onStartScreenPinning(event.applicationContext);
+ mImpl.onStartScreenPinning(event.applicationContext, event.taskId);
} else {
postToSystemUser(new Runnable() {
@Override
public void run() {
try {
- mUserToSystemCallbacks.startScreenPinning();
+ mUserToSystemCallbacks.startScreenPinning(event.taskId);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index c230cd8..618a2e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -221,11 +221,11 @@
* visibility change events through to the system user via
* {@link Recents#onBusEvent(ScreenPinningRequestEvent)}.
*/
- public void onStartScreenPinning(Context context) {
+ public void onStartScreenPinning(Context context, int taskId) {
SystemUIApplication app = (SystemUIApplication) context;
PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class);
if (statusBar != null) {
- statusBar.showScreenPinningRequest(false);
+ statusBar.showScreenPinningRequest(taskId, false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index ffeb4a1..913da18 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -82,8 +82,8 @@
}
@Override
- public void startScreenPinning() {
- mImpl.onStartScreenPinning(mContext);
+ public void startScreenPinning(int taskId) {
+ mImpl.onStartScreenPinning(mContext, taskId);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 13d4acb..7a604ca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -52,6 +52,9 @@
private RequestWindowView mRequestWindow;
+ // Id of task to be pinned or locked.
+ private int taskId;
+
public ScreenPinningRequest(Context context) {
mContext = context;
mAccessibilityService = (AccessibilityManager)
@@ -67,9 +70,11 @@
}
}
- public void showPrompt(boolean allowCancel) {
+ public void showPrompt(int taskId, boolean allowCancel) {
clearPrompt();
+ this.taskId = taskId;
+
mRequestWindow = new RequestWindowView(mContext, allowCancel);
mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
@@ -106,7 +111,7 @@
public void onClick(View v) {
if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) {
try {
- ActivityManagerNative.getDefault().startLockTaskModeOnCurrent();
+ ActivityManagerNative.getDefault().startSystemLockTaskMode(taskId);
} catch (RemoteException e) {}
}
clearPrompt();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
index 75e459a..d460917 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java
@@ -26,8 +26,10 @@
public class ScreenPinningRequestEvent extends EventBus.Event {
public final Context applicationContext;
+ public final int taskId;
- public ScreenPinningRequestEvent(Context context) {
+ public ScreenPinningRequestEvent(Context context, int taskId) {
this.applicationContext = context.getApplicationContext();
+ this.taskId = taskId;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2d5addb..63bcc2d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -99,6 +99,7 @@
static {
sBitmapOptions = new BitmapFactory.Options();
sBitmapOptions.inMutable = true;
+ sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
}
final static List<String> sRecentsBlacklist;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index fd8df99..db5413f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -77,12 +77,17 @@
private Handler mHandler;
private TaskViewTransform mTmpTransform = new TaskViewTransform();
- private Runnable mStartScreenPinningRunnable = new Runnable() {
+ private class StartScreenPinningRunnableRunnable implements Runnable {
+
+ private int taskId = -1;
+
@Override
public void run() {
- EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext));
+ EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext, taskId));
}
- };
+ }
+ private StartScreenPinningRunnableRunnable mStartScreenPinningRunnable
+ = new StartScreenPinningRunnableRunnable();
public RecentsTransitionHelper(Context context) {
mContext = context;
@@ -120,6 +125,7 @@
if (screenPinningRequested) {
// Request screen pinning after the animation runs
+ mStartScreenPinningRunnable.taskId = task.key.id;
mHandler.postDelayed(mStartScreenPinningRunnable, 350);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 2bf0b40..5d1a61d 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -39,6 +39,7 @@
private DockDividerVisibilityListener mDockDividerVisibilityListener;
private boolean mVisible = false;
private boolean mMinimized = false;
+ private boolean mAdjustedForIme = false;
private ForcedResizableInfoActivityController mForcedResizableController;
@Override
@@ -84,7 +85,7 @@
addDivider(configuration);
if (mMinimized) {
mView.setMinimizedDockStack(true);
- mWindowManager.setTouchable(false);
+ updateTouchable();
}
}
@@ -109,7 +110,7 @@
public void run() {
if (mMinimized != minimized) {
mMinimized = minimized;
- mWindowManager.setTouchable(!minimized);
+ updateTouchable();
if (animDuration > 0) {
mView.setMinimizedDockStack(minimized, animDuration);
} else {
@@ -129,6 +130,10 @@
});
}
+ private void updateTouchable() {
+ mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme);
+ }
+
class DockDividerVisibilityListener extends IDockedStackListener.Stub {
@Override
@@ -148,6 +153,22 @@
}
@Override
+ public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
+ throws RemoteException {
+ mView.post(() -> {
+ if (mAdjustedForIme != adjustedForIme) {
+ mAdjustedForIme = adjustedForIme;
+ updateTouchable();
+ if (animDuration > 0) {
+ mView.setAdjustedForIme(adjustedForIme, animDuration);
+ } else {
+ mView.setAdjustedForIme(adjustedForIme);
+ }
+ }
+ });
+ }
+
+ @Override
public void onDockSideChanged(final int newDockSide) throws RemoteException {
mView.post(() -> mView.notifyDockSideChanged(newDockSide));
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 66a413c..4d1c6ba 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -31,7 +31,6 @@
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
-import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.Display;
import android.view.DisplayInfo;
@@ -61,7 +60,6 @@
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.recents.Constants.Metrics;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -98,6 +96,7 @@
* How much the background gets scaled when we are in the minimized dock state.
*/
private static final float MINIMIZE_DOCK_SCALE = 0f;
+ private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
@@ -147,6 +146,7 @@
private int mExitStartPosition;
private GestureDetector mGestureDetector;
private boolean mDockedStackMinimized;
+ private boolean mAdjustedForIme;
private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
@Override
@@ -657,6 +657,40 @@
mDockedStackMinimized = minimized;
}
+ public void setAdjustedForIme(boolean adjustedForIme) {
+ updateDockSide();
+ mHandle.setAlpha(adjustedForIme ? 0f : 1f);
+ if (!adjustedForIme) {
+ resetBackground();
+ } else if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
+ }
+ mAdjustedForIme = adjustedForIme;
+ }
+
+ public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
+ updateDockSide();
+ mHandle.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .alpha(adjustedForIme ? 0f : 1f)
+ .start();
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.animate()
+ .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f);
+ }
+ if (!adjustedForIme) {
+ mBackground.animate().withEndAction(mResetBackgroundRunnable);
+ }
+ mBackground.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .start();
+ mAdjustedForIme = adjustedForIme;
+ }
+
private void resetBackground() {
mBackground.setPivotX(mBackground.getWidth() / 2);
mBackground.setPivotY(mBackground.getHeight() / 2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 99b6397..cc8e3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -114,7 +114,7 @@
void buzzBeepBlinked();
void notificationLightOff();
void notificationLightPulse(int argb, int onMillis, int offMillis);
- void showScreenPinningRequest();
+ void showScreenPinningRequest(int taskId);
void appTransitionPending();
void appTransitionCancelled();
void appTransitionStarting(long startTime, long duration);
@@ -298,9 +298,10 @@
}
}
- public void showScreenPinningRequest() {
+ public void showScreenPinningRequest(int taskId) {
synchronized (mLock) {
- mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST);
+ mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null)
+ .sendToTarget();
}
}
@@ -450,7 +451,7 @@
mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
break;
case MSG_SHOW_SCREEN_PIN_REQUEST:
- mCallbacks.showScreenPinningRequest();
+ mCallbacks.showScreenPinningRequest(msg.arg1);
break;
case MSG_APP_TRANSITION_PENDING:
mCallbacks.appTransitionPending();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 3c464d5..057b020 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -22,12 +22,14 @@
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.View;
@@ -60,10 +62,18 @@
private int mActualHeight;
private boolean mExposed;
private INotificationManager mINotificationManager;
- private int mStartingImportance;
+ private int mStartingUserImportance;
+ private int mNotificationImportance;
private boolean mShowSlider;
private SeekBar mSeekBar;
+ private ImageView mAutoButton;
+ private ColorStateList mActiveSliderTint;
+ private ColorStateList mInactiveSliderTint;
+ private TextView mImportanceSummary;
+ private TextView mImportanceTitle;
+ private boolean mAuto;
+
private RadioButton mBlock;
private RadioButton mSilent;
private RadioButton mReset;
@@ -145,9 +155,14 @@
void bindImportance(final PackageManager pm, final StatusBarNotification sbn,
final ExpandableNotificationRow row, final int importance) {
- mStartingImportance = importance;
mINotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ try {
+ mStartingUserImportance =
+ mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
+ } catch (RemoteException e) {}
+ mNotificationImportance = importance;
boolean systemApp = false;
try {
final PackageInfo info =
@@ -160,29 +175,25 @@
final View importanceSlider = row.findViewById(R.id.importance_slider);
final View importanceButtons = row.findViewById(R.id.importance_buttons);
if (mShowSlider) {
- bindSlider(importanceSlider, sbn, systemApp);
+ bindSlider(importanceSlider, systemApp);
importanceSlider.setVisibility(View.VISIBLE);
importanceButtons.setVisibility(View.GONE);
} else {
- mStartingImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
- try {
- mStartingImportance =
- mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
- } catch (RemoteException e) {}
- bindToggles(importanceButtons, mStartingImportance, systemApp);
+
+ bindToggles(importanceButtons, mStartingUserImportance, systemApp);
importanceButtons.setVisibility(View.VISIBLE);
importanceSlider.setVisibility(View.GONE);
}
}
public boolean hasImportanceChanged() {
- return mStartingImportance != getSelectedImportance();
+ return mStartingUserImportance != getSelectedImportance();
}
void saveImportance(final StatusBarNotification sbn) {
int progress = getSelectedImportance();
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
- progress - mStartingImportance);
+ progress - mStartingUserImportance);
try {
mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
} catch (RemoteException e) {
@@ -192,14 +203,18 @@
private int getSelectedImportance() {
if (mSeekBar!= null && mSeekBar.isShown()) {
- return mSeekBar.getProgress();
+ if (mSeekBar.isEnabled()) {
+ return mSeekBar.getProgress();
+ } else {
+ return Ranking.IMPORTANCE_UNSPECIFIED;
+ }
} else {
if (mBlock.isChecked()) {
- return NotificationListenerService.Ranking.IMPORTANCE_NONE;
+ return Ranking.IMPORTANCE_NONE;
} else if (mSilent.isChecked()) {
- return NotificationListenerService.Ranking.IMPORTANCE_LOW;
+ return Ranking.IMPORTANCE_LOW;
} else {
- return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+ return Ranking.IMPORTANCE_UNSPECIFIED;
}
}
}
@@ -229,16 +244,14 @@
}
}
- private void bindSlider(final View importanceSlider, final StatusBarNotification sbn,
- final boolean systemApp) {
- final TextView importanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary));
- final TextView importanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
+ private void bindSlider(final View importanceSlider, final boolean systemApp) {
+ mActiveSliderTint = loadColorStateList(R.color.notification_guts_slider_color);
+ mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color);
+
+ mImportanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary));
+ mImportanceTitle = ((TextView) importanceSlider.findViewById(R.id.title));
mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar);
- if (systemApp) {
- ((ImageView) importanceSlider.findViewById(R.id.low_importance)).getDrawable().setTint(
- mContext.getColor(R.color.notification_guts_disabled_icon_tint));
- }
final int minProgress = systemApp ?
NotificationListenerService.Ranking.IMPORTANCE_MIN
: NotificationListenerService.Ranking.IMPORTANCE_NONE;
@@ -267,42 +280,80 @@
// no-op
}
- private void updateTitleAndSummary(int progress) {
- switch (progress) {
- case NotificationListenerService.Ranking.IMPORTANCE_NONE:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_blocked));
- importanceTitle.setText(mContext.getString(R.string.blocked_importance));
- break;
- case NotificationListenerService.Ranking.IMPORTANCE_MIN:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_min));
- importanceTitle.setText(mContext.getString(R.string.min_importance));
- break;
- case NotificationListenerService.Ranking.IMPORTANCE_LOW:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_low));
- importanceTitle.setText(mContext.getString(R.string.low_importance));
- break;
- case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_default));
- importanceTitle.setText(mContext.getString(R.string.default_importance));
- break;
- case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_high));
- importanceTitle.setText(mContext.getString(R.string.high_importance));
- break;
- case NotificationListenerService.Ranking.IMPORTANCE_MAX:
- importanceSummary.setText(mContext.getString(
- R.string.notification_importance_max));
- importanceTitle.setText(mContext.getString(R.string.max_importance));
- break;
- }
+
+ });
+ mSeekBar.setProgress(mNotificationImportance);
+
+ mAutoButton = (ImageView) importanceSlider.findViewById(R.id.auto_importance);
+ mAutoButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mAuto = !mAuto;
+ applyAuto();
}
});
- mSeekBar.setProgress(mStartingImportance);
+ mAuto = mStartingUserImportance == Ranking.IMPORTANCE_UNSPECIFIED;
+ applyAuto();
+ }
+
+ private void applyAuto() {
+ mSeekBar.setEnabled(!mAuto);
+
+ final ColorStateList tint = mAuto ? mInactiveSliderTint : mActiveSliderTint;
+ Drawable icon = mAutoButton.getDrawable().mutate();
+ icon.setTintList(tint);
+ mAutoButton.setImageDrawable(icon);
+ mSeekBar.setProgressTintList(tint);
+ mSeekBar.setThumbTintList(tint);
+
+ if (mAuto) {
+ mSeekBar.setProgress(mNotificationImportance);
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_user_unspecified));
+ mImportanceTitle.setText(mContext.getString(
+ R.string.user_unspecified_importance));
+ } else {
+ updateTitleAndSummary(mSeekBar.getProgress());
+ }
+ }
+
+ private void updateTitleAndSummary(int progress) {
+ switch (progress) {
+ case Ranking.IMPORTANCE_NONE:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_blocked));
+ mImportanceTitle.setText(mContext.getString(R.string.blocked_importance));
+ break;
+ case Ranking.IMPORTANCE_MIN:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_min));
+ mImportanceTitle.setText(mContext.getString(R.string.min_importance));
+ break;
+ case Ranking.IMPORTANCE_LOW:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_low));
+ mImportanceTitle.setText(mContext.getString(R.string.low_importance));
+ break;
+ case Ranking.IMPORTANCE_DEFAULT:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_default));
+ mImportanceTitle.setText(mContext.getString(R.string.default_importance));
+ break;
+ case Ranking.IMPORTANCE_HIGH:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_high));
+ mImportanceTitle.setText(mContext.getString(R.string.high_importance));
+ break;
+ case Ranking.IMPORTANCE_MAX:
+ mImportanceSummary.setText(mContext.getString(
+ R.string.notification_importance_max));
+ mImportanceTitle.setText(mContext.getString(R.string.max_importance));
+ break;
+ }
+ }
+
+ private ColorStateList loadColorStateList(int colorResId) {
+ return ColorStateList.valueOf(mContext.getColor(colorResId));
}
public void closeControls(int x, int y, boolean notify) {
@@ -353,7 +404,6 @@
@Override
public boolean hasOverlappingRendering() {
-
// Prevents this view from creating a layer when alpha is animating.
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 3812429..92f3585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -21,8 +21,12 @@
import android.app.IWallpaperManagerCallback;
import android.app.WallpaperManager;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.DrawableWrapper;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
@@ -151,4 +155,57 @@
getBitmap();
mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */);
}
+
+ /**
+ * Drawable that aligns left horizontally and center vertically (like ImageWallpaper).
+ */
+ public static class WallpaperDrawable extends DrawableWrapper {
+
+ private Bitmap mBackground;
+ private Rect mTmpRect = new Rect();
+
+ public WallpaperDrawable(Resources r, Bitmap b) {
+ super(new BitmapDrawable(r, b));
+ mBackground = b;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return -1;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return -1;
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ int vwidth = getBounds().width();
+ int vheight = getBounds().height();
+ int dwidth = mBackground.getWidth();
+ int dheight = mBackground.getHeight();
+ float scale;
+ float dx = 0, dy = 0;
+
+ if (dwidth * vheight > vwidth * dheight) {
+ scale = (float) vheight / (float) dheight;
+ } else {
+ scale = (float) vwidth / (float) dwidth;
+ }
+
+ if (scale <= 1f) {
+ scale = 1f;
+ }
+ dy = (vheight - dheight * scale) * 0.5f;
+
+ mTmpRect.set(
+ bounds.left,
+ bounds.top + Math.round(dy),
+ bounds.left + Math.round(dwidth * scale),
+ bounds.top + Math.round(dheight * scale + dy));
+
+ super.onBoundsChange(mTmpRect);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
index 41eed56..951b096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java
@@ -15,6 +15,7 @@
package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
+import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -57,10 +58,18 @@
}
}
- public void setWorkModeEnabled(boolean enabled) {
+ public void setWorkModeEnabled(boolean enableWorkMode) {
synchronized (mProfiles) {
for (UserInfo ui : mProfiles) {
- mUserManager.setQuietModeEnabled(ui.id, !enabled);
+ if (enableWorkMode) {
+ if (!mUserManager.trySetQuietModeDisabled(ui.id, null)) {
+ StatusBarManager statusBarManager = (StatusBarManager) mContext
+ .getSystemService(android.app.Service.STATUS_BAR_SERVICE);
+ statusBarManager.collapsePanels();
+ }
+ } else {
+ mUserManager.setQuietModeEnabled(ui.id, true);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 581b611..4b7d56b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -372,7 +372,10 @@
mDisabledFlags = disabledFlags;
final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
- boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
+
+ // Disable recents always in car mode.
+ boolean disableRecent = (
+ mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
&& ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
@@ -528,6 +531,11 @@
}
@Override
+ public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
+ throws RemoteException {
+ }
+
+ @Override
public void onDockSideChanged(int newDockSide) throws RemoteException {
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3ca0a6d..82806fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -46,6 +46,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
@@ -1928,19 +1929,27 @@
+ " state=" + mState);
}
- Bitmap artworkBitmap = null;
+ Drawable artworkDrawable = null;
if (mMediaMetadata != null) {
+ Bitmap artworkBitmap = null;
artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
if (artworkBitmap == null) {
artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
// might still be null
}
+ if (artworkBitmap != null) {
+ artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
+ }
}
- if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
- artworkBitmap = mLockscreenWallpaper.getBitmap();
+ if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
+ Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
+ if (lockWallpaper != null) {
+ artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
+ mBackdropBack.getResources(), lockWallpaper);
+ }
}
- final boolean hasArtwork = artworkBitmap != null;
+ final boolean hasArtwork = artworkDrawable != null;
if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE
&& mFingerprintUnlockController.getMode()
@@ -1985,7 +1994,7 @@
mBackdropBack.setBackgroundColor(0xFFFFFFFF);
mBackdropBack.setImageDrawable(new ColorDrawable(c));
} else {
- mBackdropBack.setImageBitmap(artworkBitmap);
+ mBackdropBack.setImageDrawable(artworkDrawable);
}
if (mScrimSrcModeEnabled) {
mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode);
@@ -4314,7 +4323,7 @@
try {
IActivityManager activityManager = ActivityManagerNative.getDefault();
if (activityManager.isInLockTaskMode()) {
- activityManager.stopLockTaskModeOnCurrent();
+ activityManager.stopSystemLockTaskMode();
// When exiting refresh disabled flags.
mNavigationBarView.setDisabledFlags(mDisabled1, true);
@@ -4337,17 +4346,17 @@
}
@Override
- public void showScreenPinningRequest() {
+ public void showScreenPinningRequest(int taskId) {
if (mKeyguardMonitor.isShowing()) {
// Don't allow apps to trigger this from keyguard.
return;
}
// Show screen pinning request, since this comes from an app, show 'no thanks', button.
- showScreenPinningRequest(true);
+ showScreenPinningRequest(taskId, true);
}
- public void showScreenPinningRequest(boolean allowCancel) {
- mScreenPinningRequest.showPrompt(allowCancel);
+ public void showScreenPinningRequest(int taskId, boolean allowCancel) {
+ mScreenPinningRequest.showPrompt(taskId, allowCancel);
}
public boolean hasActiveNotifications() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index acef81b..f9202c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -165,7 +165,7 @@
}
@Override
- public void showScreenPinningRequest() {
+ public void showScreenPinningRequest(int taskId) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
new file mode 100644
index 0000000..205db32
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.systemui.tuner;
+
+import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import com.android.systemui.R;
+
+public class OtherPrefs extends PreferenceFragment {
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.other_settings);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
new file mode 100644
index 0000000..14fccf2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2016, 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.systemui.tuner;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+import android.widget.TextView;
+
+public class PowerNotificationControlsFragment extends Fragment {
+
+ private static final String KEY_SHOW_PNC = "show_importance_slider";
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.power_notification_controls_settings, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ final View switchBar = view.findViewById(R.id.switch_bar);
+ final Switch switchWidget = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+ final TextView switchText = (TextView) switchBar.findViewById(R.id.switch_text);
+ switchWidget.setChecked(isEnabled());
+ switchText.setText(isEnabled()
+ ? getString(R.string.switch_bar_on)
+ : getString(R.string.switch_bar_off));
+
+ switchWidget.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean newState = !isEnabled();
+ MetricsLogger.action(getContext(),
+ MetricsEvent.ACTION_TUNER_POWER_NOTIFICATION_CONTROLS, newState);
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ KEY_SHOW_PNC, newState ? 1 : 0);
+ switchWidget.setChecked(newState);
+ switchText.setText(newState
+ ? getString(R.string.switch_bar_on)
+ : getString(R.string.switch_bar_off));
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MetricsLogger.visibility(
+ getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, true);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ MetricsLogger.visibility(
+ getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, false);
+ }
+
+ private boolean isEnabled() {
+ int setting = Settings.Secure.getInt(getContext().getContentResolver(), KEY_SHOW_PNC, 0);
+ return setting == 1;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index a445e77..5febb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -35,6 +35,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -144,6 +145,7 @@
private ComponentName mPipComponentName;
private MediaController mPipMediaController;
private boolean mOnboardingShown;
+ private String[] mLastPackagesResourceGranted;
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
@@ -166,7 +168,7 @@
String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE,
INVALID_RESOURCE_TYPE);
- if (mState != STATE_NO_PIP && packageNames != null && packageNames.length > 0
+ if (packageNames != null && packageNames.length > 0
&& resourceType == Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC) {
handleMediaResourceGranted(packageNames);
}
@@ -446,41 +448,24 @@
}
private void handleMediaResourceGranted(String[] packageNames) {
- StackInfo fullscreenStack = null;
- try {
- fullscreenStack = mActivityManager.getStackInfo(FULLSCREEN_WORKSPACE_STACK_ID);
- } catch (RemoteException e) {
- Log.e(TAG, "getStackInfo failed", e);
- }
- if (fullscreenStack == null) {
- return;
- }
- int fullscreenTopTaskId = fullscreenStack.taskIds[fullscreenStack.taskIds.length - 1];
- List<RunningTaskInfo> tasks = null;
- try {
- tasks = mActivityManager.getTasks(MAX_RUNNING_TASKS_COUNT, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "getTasks failed", e);
- }
- if (tasks == null) {
- return;
- }
- boolean wasGrantedInFullscreen = false;
- boolean wasGrantedInPip = false;
- for (int i = tasks.size() - 1; i >= 0; --i) {
- RunningTaskInfo task = tasks.get(i);
- for (int j = packageNames.length - 1; j >= 0; --j) {
- if (task.topActivity.getPackageName().equals(packageNames[j])) {
- if (task.id == fullscreenTopTaskId) {
- wasGrantedInFullscreen = true;
- } else if (task.id == mPipTaskId) {
- wasGrantedInPip= true;
+ if (mState == STATE_NO_PIP) {
+ mLastPackagesResourceGranted = packageNames;
+ } else {
+ boolean requestedFromLastPackages = false;
+ if (mLastPackagesResourceGranted != null) {
+ for (String packageName : mLastPackagesResourceGranted) {
+ for (String newPackageName : packageNames) {
+ if (TextUtils.equals(newPackageName, packageName)) {
+ requestedFromLastPackages = true;
+ break;
+ }
}
}
}
- }
- if (wasGrantedInFullscreen && !wasGrantedInPip) {
- closePip();
+ mLastPackagesResourceGranted = packageNames;
+ if (!requestedFromLastPackages) {
+ closePip();
+ }
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index afea7f3..7b3fd66 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2152,6 +2152,23 @@
// User tried to dock an unresizable app.
ACTION_WINDOW_DOCK_UNRESIZABLE = 391;
+ // System UI Tuner > Other > Power notification controls
+ TUNER_POWER_NOTIFICATION_CONTROLS = 392;
+
+ // System UI Tuner > Other > Power notification controls > Toggle on/off
+ ACTION_TUNER_POWER_NOTIFICATION_CONTROLS = 393;
+
+ // Action: user enable / disabled data saver using Settings. Arguments:
+ // 0: Data Saver mode is disabled.
+ // 1: Data Saver mode is enabled.
+ ACTION_DATA_SAVER_MODE = 394;
+
+ // User whitelisted an app for Data Saver mode; action pass package name of app.
+ ACTION_DATA_SAVER_WHITELIST = 395;
+
+ // User blacklisted an app for Data Saver mode; action pass package name of app.
+ ACTION_DATA_SAVER_BLACKLIST = 396;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 99c5dd6..a248aa3 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -4,11 +4,14 @@
LOCAL_MODULE := services.core
+LOCAL_AIDL_INCLUDES := system/netd/server/binder
+
LOCAL_SRC_FILES += \
$(call all-java-files-under,java) \
java/com/android/server/EventLogTags.logtags \
java/com/android/server/am/EventLogTags.logtags \
- ../../../../system/netd/server/binder/android/net/INetd.aidl
+ ../../../../system/netd/server/binder/android/net/INetd.aidl \
+ ../../../../system/netd/server/binder/android/net/metrics/IDnsEventListener.aidl \
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f2b4e52..c1bacfa 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -261,7 +261,9 @@
showEncryptionNotification(userHandle);
} else {
UserInfo parent = mUserManager.getProfileParent(user.id);
- if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) {
+ if (parent != null &&
+ mUserManager.isUserUnlocked(parent.getUserHandle()) &&
+ !mUserManager.isQuietModeEnabled(userHandle)) {
// Only show notifications for managed profiles once their parent
// user is unlocked.
showEncryptionNotificationForProfile(userHandle);
@@ -348,7 +350,8 @@
UserInfo profile = profiles.get(i);
if (profile.isManagedProfile()) {
UserHandle userHandle = profile.getUserHandle();
- if (!mUserManager.isUserUnlocked(userHandle)) {
+ if (!mUserManager.isUserUnlocked(userHandle) &&
+ !mUserManager.isQuietModeEnabled(userHandle)) {
showEncryptionNotificationForProfile(userHandle);
}
}
@@ -702,6 +705,12 @@
}
};
+ // Check if the user is currently in quiet mode and start it otherwise
+ if (mUserManager.isQuietModeEnabled(new UserHandle(userId))
+ && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+ mUserManager.setQuietModeEnabled(userId, false);
+ }
+
try {
ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9703d13..40430b4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1471,6 +1471,7 @@
static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68;
+ static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2241,6 +2242,17 @@
}
vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
} break;
+ case VR_MODE_APPLY_IF_NEEDED_MSG: {
+ final ActivityRecord r = (ActivityRecord) msg.obj;
+ final boolean needsVrMode = r != null && r.requestedVrComponent != null;
+ if (needsVrMode) {
+ VrManagerInternal vrService =
+ LocalServices.getService(VrManagerInternal.class);
+ boolean enable = msg.arg1 == 1;
+ vrService.setVrMode(enable, r.requestedVrComponent, r.userId,
+ r.info.getComponentName());
+ }
+ } break;
}
}
};
@@ -3021,6 +3033,11 @@
mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
}
+ private void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r));
+ }
+
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -6537,6 +6554,7 @@
// Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ applyVrModeIfNeededLocked(mFocusedActivity, true);
}
}
} finally {
@@ -9873,7 +9891,6 @@
boolean isSystemInitiated = callingUid == Process.SYSTEM_UID;
long ident = Binder.clearCallingIdentity();
try {
- final ActivityStack stack = mStackSupervisor.getFocusedStack();
if (!isSystemInitiated) {
task.mLockTaskUid = callingUid;
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
@@ -9882,11 +9899,12 @@
StatusBarManagerInternal statusBarManager =
LocalServices.getService(StatusBarManagerInternal.class);
if (statusBarManager != null) {
- statusBarManager.showScreenPinningRequest();
+ statusBarManager.showScreenPinningRequest(task.taskId);
}
return;
}
+ final ActivityStack stack = mStackSupervisor.getFocusedStack();
if (stack == null || task != stack.topTask()) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
@@ -9927,15 +9945,13 @@
}
@Override
- public void startLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent");
+ public void startSystemLockTaskMode(int taskId) throws RemoteException {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
+ // This makes inner call to look as if it was initiated by system.
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- ActivityRecord r = mStackSupervisor.topRunningActivityLocked();
- if (r != null) {
- startLockTaskModeLocked(r.task);
- }
+ startLockTaskMode(taskId);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9979,8 +9995,9 @@
}
@Override
- public void stopLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent");
+ public void stopSystemLockTaskMode() throws RemoteException {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode");
+ // This makes inner call to look as if it was initiated by system.
long ident = Binder.clearCallingIdentity();
try {
stopLockTaskMode();
@@ -20926,6 +20943,7 @@
SleepTokenImpl token = new SleepTokenImpl(tag);
mSleepTokens.add(token);
updateSleepIfNeededLocked();
+ applyVrModeIfNeededLocked(mFocusedActivity, false);
return token;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 43e1bdf..0331470 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -98,13 +98,16 @@
* launch
* @param componentName the component name of the activity being launched
* @param processRunning whether the process that will contains the activity is already running
+ * @param processSwitch whether the process that will contain the activity didn't have any
+ * activity that was stopped, i.e. the started activity is "switching"
+ * processes
*/
void notifyActivityLaunched(int resultCode, @Nullable String componentName,
- boolean processRunning) {
+ boolean processRunning, boolean processSwitch) {
- if (resultCode < 0 || componentName == null) {
+ if (resultCode < 0 || componentName == null || !processSwitch) {
- // Failed to launch, don't track anything.
+ // Failed to launch or it was not a process switch, so we don't care about the timing.
reset();
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6fba8c8..a96f23a 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -137,6 +137,7 @@
// Share state variable among methods when starting an activity.
private ActivityRecord mStartActivity;
+ private ActivityRecord mReusedActivity;
private Intent mIntent;
private int mCallingUid;
private ActivityOptions mOptions;
@@ -785,15 +786,40 @@
final String componentName = outRecord[0] != null ? outRecord[0].shortComponentName
: null;
- final boolean processRunning = outRecord[0] != null &&
- mService.mProcessNames.get(outRecord[0].processName,
- outRecord[0].appInfo.uid) != null;
+ final ActivityRecord launchedActivity = mReusedActivity != null
+ ? mReusedActivity : outRecord[0];
+ final ProcessRecord processRecord = launchedActivity != null
+ ? mService.mProcessNames.get(launchedActivity.processName,
+ launchedActivity.appInfo.uid)
+ : null;
+ final boolean processRunning = processRecord != null;
+
+ // We consider this a "process switch" if the process of the activity that gets launched
+ // didn't have an activity that was in started state. In this case, we assume that lot
+ // of caches might be purged so the time until it produces the first frame is very
+ // interesting.
+ final boolean processSwitch = processRecord == null
+ || !hasStartedActivity(processRecord, launchedActivity);
mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, componentName,
- processRunning);
+ processRunning, processSwitch);
return res;
}
}
+ final boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
+ final ArrayList<ActivityRecord> activities = record.activities;
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ final ActivityRecord activity = activities.get(i);
+ if (launchedActivity == activity) {
+ continue;
+ }
+ if (!activity.stopped) {
+ return true;
+ }
+ }
+ return false;
+ }
+
final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo,
Bundle bOptions, int userId) {
@@ -883,16 +909,16 @@
mIntent.setFlags(mLaunchFlags);
- ActivityRecord intentActivity = getReusableIntentActivity();
+ mReusedActivity = getReusableIntentActivity();
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
- if (intentActivity != null) {
+ if (mReusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
// the device would otherwise leave the locked task.
- if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
+ if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task,
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
mSupervisor.showLockTaskToast();
@@ -901,12 +927,12 @@
}
if (mStartActivity.task == null) {
- mStartActivity.task = intentActivity.task;
+ mStartActivity.task = mReusedActivity.task;
}
- if (intentActivity.task.intent == null) {
+ if (mReusedActivity.task.intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
- intentActivity.task.setIntent(mStartActivity);
+ mReusedActivity.task.setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
@@ -917,7 +943,7 @@
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
- final ActivityRecord top = intentActivity.task.performClearTaskForReuseLocked(
+ final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
mStartActivity, mLaunchFlags);
if (top != null) {
if (top.frontOfTask) {
@@ -931,7 +957,7 @@
}
}
- intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
+ mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do anything
@@ -941,7 +967,7 @@
return START_RETURN_INTENT_TO_CALLER;
}
- setTaskFromIntentActivity(intentActivity);
+ setTaskFromIntentActivity(mReusedActivity);
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index e69c662..08d2399 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1501,22 +1501,22 @@
Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
config.screenHeightDp =
Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
- config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp);
// TODO: Orientation?
config.orientation = (config.screenWidthDp <= config.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
- // For calculating screen layout, we need to use the non-decor inset screen area for the
- // calculation for compatibility reasons, i.e. screen area without system bars that could
- // never go away in Honeycomb.
+ // For calculating screen layout and smallest screen width, we need to use the non-decor
+ // inset screen area for the calculation for compatibility reasons, i.e. screen area without
+ // system bars that could never go away in Honeycomb.
final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
- final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
- config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
+ config.smallestScreenWidthDp = Math.min(compatScreenHeightDp, compatScreenWidthDp);
+ config.screenLayout = Configuration.reduceScreenLayout(sl, longSize,
+ config.smallestScreenWidthDp);
return config;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5ebb9a7..4292fcf 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -895,7 +895,10 @@
synchronized (mService) {
// Bail if already running unlocked, or if not running at all
final UserState uss = mStartedUsers.get(userId);
- if (uss == null) return false;
+ if (uss == null) {
+ progress.finish();
+ return false;
+ }
switch (uss.state) {
case STATE_RUNNING_UNLOCKING:
case STATE_RUNNING_UNLOCKED:
diff --git a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
new file mode 100644
index 0000000..d3f8af0
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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.connectivity;
+
+import android.content.Context;
+import android.net.metrics.DnsEvent;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.metrics.IDnsEventListener;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+
+/**
+ * Implementation of the IDnsEventListener interface.
+ */
+public class DnsEventListenerService extends IDnsEventListener.Stub {
+
+ public static final String SERVICE_NAME = "dns_listener";
+
+ private static final String TAG = DnsEventListenerService.class.getSimpleName();
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100;
+
+ // Stores the results of a number of consecutive DNS lookups on the same network.
+ // This class is not thread-safe and it is the responsibility of the service to call its methods
+ // on one thread at a time.
+ private static class DnsEventBatch {
+ private final int mNetId;
+
+ private final byte[] mEventTypes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
+ private final byte[] mReturnCodes = new byte[MAX_LOOKUPS_PER_DNS_EVENT];
+ private final int[] mLatenciesMs = new int[MAX_LOOKUPS_PER_DNS_EVENT];
+ private int mEventCount;
+
+ public DnsEventBatch(int netId) {
+ mNetId = netId;
+ }
+
+ public void addResult(byte eventType, byte returnCode, int latencyMs) {
+ mEventTypes[mEventCount] = eventType;
+ mReturnCodes[mEventCount] = returnCode;
+ mLatenciesMs[mEventCount] = latencyMs;
+ mEventCount++;
+ if (mEventCount == MAX_LOOKUPS_PER_DNS_EVENT) {
+ logAndClear();
+ }
+ }
+
+ public void logAndClear() {
+ // Did we lose a race with addResult?
+ if (mEventCount == 0) {
+ return;
+ }
+
+ byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount);
+ int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount);
+ DnsEvent.logEvent(mNetId, mEventTypes, mReturnCodes, mLatenciesMs);
+ maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId));
+ mEventCount = 0;
+ }
+
+ // For debugging and unit tests only.
+ public String toString() {
+ return String.format("%s %d %d", getClass().getSimpleName(), mNetId, mEventCount);
+ }
+ }
+
+ // Only sorted for ease of debugging. Because we only typically have a handful of networks up
+ // at any given time, performance is not a concern.
+ @GuardedBy("this")
+ private SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>();
+
+ // We register a NetworkCallback to ensure that when a network disconnects, we flush the DNS
+ // queries we've logged on that network. Because we do not do this periodically, we might lose
+ // up to MAX_LOOKUPS_PER_DNS_EVENT lookup stats on each network when the system is shutting
+ // down. We believe this to be sufficient for now.
+ private final ConnectivityManager mCm;
+ private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+ @Override
+ public void onLost(Network network) {
+ synchronized (DnsEventListenerService.this) {
+ DnsEventBatch batch = mEventBatches.remove(network.netId);
+ if (batch != null) {
+ batch.logAndClear();
+ }
+ }
+ }
+ };
+
+ public DnsEventListenerService(Context context) {
+ // We are started when boot is complete, so ConnectivityService should already be running.
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .build();
+ mCm = context.getSystemService(ConnectivityManager.class);
+ mCm.registerNetworkCallback(request, mNetworkCallback);
+ }
+
+ @Override
+ // Called concurrently by multiple binder threads.
+ public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs) {
+ maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
+ netId, eventType, returnCode, latencyMs));
+
+ DnsEventBatch batch = mEventBatches.get(netId);
+ if (batch == null) {
+ batch = new DnsEventBatch(netId);
+ mEventBatches.put(netId, batch);
+ }
+ batch.addResult((byte) eventType, (byte) returnCode, latencyMs);
+ }
+
+ public synchronized void dump(PrintWriter writer) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println(TAG + ":");
+ pw.increaseIndent();
+ for (DnsEventBatch batch : mEventBatches.values()) {
+ pw.println(batch.toString());
+ }
+ pw.decreaseIndent();
+ }
+
+ private static void maybeLog(String s) {
+ if (DBG) Log.d(TAG, s);
+ }
+
+ private static void maybeVerboseLog(String s) {
+ if (VDBG) Log.d(TAG, s);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index f91db78..0c259ae 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -55,6 +55,8 @@
if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
mBinder);
+ mDnsListener = new DnsEventListenerService(getContext());
+ publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener);
}
}
@@ -89,6 +91,8 @@
private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
+ private DnsEventListenerService mDnsListener;
+
private void enforceConnectivityInternalPermission() {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CONNECTIVITY_INTERNAL,
@@ -159,10 +163,12 @@
synchronized (mEvents) {
pw.println("Number of events: " + mEvents.size());
- pw.println("Time span: " +
- DateUtils.formatElapsedTime(
- (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
- / 1000));
+ if (mEvents.size() > 0) {
+ pw.println("Time span: " +
+ DateUtils.formatElapsedTime(
+ (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
+ / 1000));
+ }
if (dumpSerializedSize) {
long dataSize = 0;
@@ -193,6 +199,9 @@
pw.println(pi.toString());
}
}
+
+ pw.println();
+ mDnsListener.dump(pw);
}
public long logEvent(ConnectivityMetricsEvent event) {
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
new file mode 100644
index 0000000..d2f015f
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright (C) 2016 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.fingerprint;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+
+import android.content.Context;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.util.Slog;
+
+/**
+ * A class to keep track of the authentication state for a given client.
+ */
+public abstract class AuthenticationClient extends ClientMonitor {
+ private long mOpId;
+
+ public abstract boolean handleFailedAttempt();
+ public abstract void resetFailedAttempts();
+
+ public AuthenticationClient(Context context, long halDeviceId, IBinder token,
+ IFingerprintServiceReceiver receiver, int userId, int groupId, long opId,
+ boolean restricted, String owner) {
+ super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
+ mOpId = opId;
+ }
+
+ @Override
+ public boolean onAuthenticated(int fingerId, int groupId) {
+ boolean result = false;
+ boolean authenticated = fingerId != 0;
+
+ IFingerprintServiceReceiver receiver = getReceiver();
+ if (receiver != null) {
+ try {
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_AUTH,
+ authenticated);
+ if (!authenticated) {
+ receiver.onAuthenticationFailed(getHalDeviceId());
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString()
+ + ", id=" + fingerId + ", gp=" + groupId + ")");
+ }
+ Fingerprint fp = !getIsRestricted()
+ ? new Fingerprint("" /* TODO */, groupId, fingerId, getHalDeviceId())
+ : null;
+ receiver.onAuthenticationSucceeded(getHalDeviceId(), fp);
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify Authenticated:", e);
+ result = true; // client failed
+ }
+ } else {
+ result = true; // client not listening
+ }
+ if (fingerId == 0) {
+ if (receiver != null) {
+ FingerprintUtils.vibrateFingerprintError(getContext());
+ }
+ // allow system-defined limit of number of attempts before giving up
+ result |= handleFailedAttempt();
+ } else {
+ if (receiver != null) {
+ FingerprintUtils.vibrateFingerprintSuccess(getContext());
+ }
+ result |= true; // we have a valid fingerprint, done
+ resetFailedAttempts();
+ }
+ return result;
+ }
+
+ /**
+ * Start authentication
+ */
+ @Override
+ public int start() {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "start authentication: no fingeprintd!");
+ return ERROR_ESRCH;
+ }
+ try {
+ final int result = daemon.authenticate(mOpId, getGroupId());
+ if (result != 0) {
+ Slog.w(TAG, "startAuthentication failed, result=" + result);
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ return result;
+ }
+ if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startAuthentication failed", e);
+ return ERROR_ESRCH;
+ }
+ return 0; // success
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "stopAuthentication: no fingeprintd!");
+ return ERROR_ESRCH;
+ }
+ try {
+ final int result = daemon.cancelAuthentication();
+ if (result != 0) {
+ Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ return result;
+ }
+ if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer authenticating");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopAuthentication failed", e);
+ return ERROR_ESRCH;
+ }
+ return 0; // success
+ }
+
+ @Override
+ public boolean onEnrollResult(int fingerId, int groupId, int rem) {
+ if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!");
+ return true; // Invalid for Authenticate
+ }
+
+ @Override
+ public boolean onRemoved(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!");
+ return true; // Invalid for Authenticate
+ }
+
+ @Override
+ public boolean onEnumerationResult(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!");
+ return true; // Invalid for Authenticate
+ }
+}
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
new file mode 100644
index 0000000..90998ed
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -0,0 +1,211 @@
+/**
+ * Copyright (C) 2016 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.fingerprint;
+
+import android.Manifest;
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Abstract base class for keeping track and dispatching events from fingerprintd to the
+ * the current client. Subclasses are responsible for coordinating the interaction with
+ * fingerprintd for the specific action (e.g. authenticate, enroll, enumerate, etc.).
+ */
+public abstract class ClientMonitor implements IBinder.DeathRecipient {
+ protected static final String TAG = FingerprintService.TAG; // TODO: get specific name
+ protected static final int ERROR_ESRCH = 3; // Likely fingerprintd is dead. See errno.h.
+ protected static final boolean DEBUG = FingerprintService.DEBUG;
+ private IBinder mToken;
+ private IFingerprintServiceReceiver mReceiver;
+ private int mUserId;
+ private int mGroupId;
+ private boolean mIsRestricted; // True if client does not have MANAGE_FINGERPRINT permission
+ private String mOwner;
+ private Context mContext;
+ private long mHalDeviceId;
+
+ /**
+ * @param context context of FingerprintService
+ * @param halDeviceId the HAL device ID of the associated fingerprint hardware
+ * @param token a unique token for the client
+ * @param receiver recipient of related events (e.g. authentication)
+ * @param userId userId for the fingerprint set
+ * @param groupId groupId for the fingerprint set
+ * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
+ * permission
+ * @param owner name of the client that owns this
+ */
+ public ClientMonitor(Context context, long halDeviceId, IBinder token,
+ IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
+ String owner) {
+ mContext = context;
+ mHalDeviceId = halDeviceId;
+ mToken = token;
+ mReceiver = receiver;
+ mUserId = userId;
+ mGroupId = groupId;
+ mIsRestricted = restricted;
+ mOwner = owner;
+ try {
+ token.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+ }
+ }
+
+ /**
+ * Contacts fingerprintd to start the client.
+ * @return 0 on succes, errno from driver on failure
+ */
+ public abstract int start();
+
+ /**
+ * Contacts fingerprintd to stop the client.
+ * @param initiatedByClient whether the operation is at the request of a client
+ */
+ public abstract int stop(boolean initiatedByClient);
+
+ /**
+ * Method to explicitly poke powermanager on events
+ */
+ public abstract void notifyUserActivity();
+
+ /**
+ * Gets the fingerprint daemon from the cached state in the container class.
+ */
+ public abstract IFingerprintDaemon getFingerprintDaemon();
+
+ // Event callbacks from driver. Inappropriate calls is flagged/logged by the
+ // respective client (e.g. enrolling shouldn't get authenticate events).
+ // All of these return 'true' if the operation is completed and it's ok to move
+ // to the next client (e.g. authentication accepts or rejects a fingerprint).
+ public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
+ public abstract boolean onAuthenticated(int fingerId, int groupId);
+ public abstract boolean onRemoved(int fingerId, int groupId);
+ public abstract boolean onEnumerationResult(int fingerId, int groupId);
+
+ /**
+ * Called when we get notification from fingerprintd that an image has been acquired.
+ * Common to authenticate and enroll.
+ * @param acquiredInfo info about the current image acquisition
+ * @return true if client should be removed
+ */
+ public boolean onAcquired(int acquiredInfo) {
+ if (mReceiver == null)
+ return true; // client not connected
+ try {
+ mReceiver.onAcquired(getHalDeviceId(), acquiredInfo);
+ return false; // acquisition continues...
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke sendAcquired:", e);
+ return true; // client failed
+ } finally {
+ // Good scans will keep the device awake
+ if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
+ notifyUserActivity();
+ }
+ }
+ }
+
+ /**
+ * Called when we get notification from fingerprintd that an error has occurred with the
+ * current operation. Common to authenticate, enroll, enumerate and remove.
+ * @param error
+ * @return true if client should be removed
+ */
+ public boolean onError(int error) {
+ if (mReceiver != null) {
+ try {
+ mReceiver.onError(getHalDeviceId(), error);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke sendError:", e);
+ }
+ }
+ return true; // errors always remove current client
+ }
+
+ public void destroy() {
+ if (mToken != null) {
+ try {
+ mToken.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ // TODO: remove when duplicate call bug is found
+ Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
+ }
+ mToken = null;
+ }
+ mReceiver = null;
+ }
+
+ @Override
+ public void binderDied() {
+ mToken = null;
+ mReceiver = null;
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mToken != null) {
+ if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public final Context getContext() {
+ return mContext;
+ }
+
+ public final long getHalDeviceId() {
+ return mHalDeviceId;
+ }
+
+ public final String getOwnerString() {
+ return mOwner;
+ }
+
+ public final IFingerprintServiceReceiver getReceiver() {
+ return mReceiver;
+ }
+
+ public final boolean getIsRestricted() {
+ return mIsRestricted;
+ }
+
+ public final int getUserId() {
+ return mUserId;
+ }
+
+ public final int getGroupId() {
+ return mGroupId;
+ }
+
+ public final IBinder getToken() {
+ return mToken;
+ }
+}
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
new file mode 100644
index 0000000..ce5b890
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) 2016 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.fingerprint;
+
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+
+import java.util.Arrays;
+
+/**
+ * A class to keep track of the enrollment state for a given client.
+ */
+public abstract class EnrollClient extends ClientMonitor {
+ private static final long MS_PER_SEC = 1000;
+ private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+ private byte[] mCryptoToken;
+
+ public EnrollClient(Context context, long halDeviceId, IBinder token,
+ IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken,
+ boolean restricted, String owner) {
+ super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
+ mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length);
+ }
+
+ @Override
+ public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
+ if (remaining == 0) {
+ FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId,
+ getUserId());
+ }
+ return sendEnrollResult(fingerId, groupId, remaining);
+ }
+
+ /*
+ * @return true if we're done.
+ */
+ private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
+ IFingerprintServiceReceiver receiver = getReceiver();
+ if (receiver == null)
+ return true; // client not listening
+
+ FingerprintUtils.vibrateFingerprintSuccess(getContext());
+ MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_ENROLL);
+ try {
+ receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining);
+ return remaining == 0;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify EnrollResult:", e);
+ return true;
+ }
+ }
+
+ @Override
+ public int start() {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "enroll: no fingeprintd!");
+ return ERROR_ESRCH;
+ }
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ try {
+ final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
+ if (result != 0) {
+ Slog.w(TAG, "startEnroll failed, result=" + result);
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startEnroll failed", e);
+ }
+ return 0; // success
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "stopEnrollment: no fingeprintd!");
+ return ERROR_ESRCH;
+ }
+ try {
+ final int result = daemon.cancelEnrollment();
+ if (result != 0) {
+ Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopEnrollment failed", e);
+ }
+ if (initiatedByClient) {
+ onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean onRemoved(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onRemoved() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+ @Override
+ public boolean onEnumerationResult(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+ @Override
+ public boolean onAuthenticated(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enroll!");
+ return true; // Invalid for EnrollClient
+ }
+
+}
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
new file mode 100644
index 0000000..b2e4099
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2016 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.fingerprint;
+
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * A class to keep track of the enumeration state for a given client.
+ */
+public abstract class EnumerateClient extends ClientMonitor {
+ public EnumerateClient(Context context, long halDeviceId, IBinder token,
+ IFingerprintServiceReceiver receiver, int userId, int groupId,
+ boolean restricted, String owner) {
+ super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
+ }
+
+ @Override
+ public int start() {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ // The fingerprint template ids will be removed when we get confirmation from the HAL
+ try {
+ final int result = daemon.enumerate();
+ if (result != 0) {
+ Slog.w(TAG, "start enumerate for user " + getUserId()
+ + " failed, result=" + result);
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startRemove failed", e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ if (daemon == null) {
+ Slog.w(TAG, "stopAuthentication: no fingeprintd!");
+ return ERROR_ESRCH;
+ }
+ try {
+ final int result = daemon.cancelEnumeration();
+ if (result != 0) {
+ Slog.w(TAG, "stop enumeration failed, result=" + result);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stop enumeration failed", e);
+ return ERROR_ESRCH;
+ }
+ // We don't actually stop enumerate, but inform the client that the cancel operation
+ // succeeded so we can start the next operation.
+ if (initiatedByClient) {
+ onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+ }
+ return 0; // success
+ }
+
+ @Override
+ public boolean onEnumerationResult(int fingerId, int groupId) {
+ IFingerprintServiceReceiver receiver = getReceiver();
+ if (receiver == null)
+ return true; // client not listening
+ try {
+ receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify enumerated:", e);
+ }
+ return fingerId == 0; // done when id hits 0
+ }
+}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index e3f3849..2dafa3e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.trust.TrustManager;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppOpsManager;
@@ -48,7 +47,6 @@
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.server.SystemService;
import org.json.JSONArray;
@@ -75,7 +73,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.NoSuchElementException;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -85,31 +82,36 @@
* @hide
*/
public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
- private static final String TAG = "FingerprintService";
- private static final boolean DEBUG = true;
+ static final String TAG = "FingerprintService";
+ static final boolean DEBUG = true;
private static final String FP_DATA_DIR = "fpdata";
private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
private static final int MSG_USER_SWITCHING = 10;
- private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
private static final String ACTION_LOCKOUT_RESET =
"com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
- private ClientMonitor mAuthClient = null;
- private ClientMonitor mEnrollClient = null;
- private ClientMonitor mRemoveClient = null;
private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
new ArrayList<>();
private final AppOpsManager mAppOps;
- private static final long MS_PER_SEC = 1000;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
private static final int MAX_FAILED_ATTEMPTS = 5;
- private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+ private static final long CANCEL_TIMEOUT_LIMIT = 300; // max wait for onCancel() from HAL,in ms
private final String mKeyguardPackage;
private int mCurrentUserId = UserHandle.USER_CURRENT;
- private int mUserIdForRemove = UserHandle.USER_NULL;
+ private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
+ private Context mContext;
+ private long mHalDeviceId;
+ private int mFailedAttempts;
+ private IFingerprintDaemon mDaemon;
+ private final PowerManager mPowerManager;
+ private final AlarmManager mAlarmManager;
+ private final UserManager mUserManager;
+ private ClientMonitor mCurrentClient;
+ private ClientMonitor mPendingClient;
+ private long mCurrentAuthenticatorId;
- Handler mHandler = new Handler() {
+ private Handler mHandler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
@@ -123,15 +125,6 @@
}
};
- private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
- private Context mContext;
- private long mHalDeviceId;
- private int mFailedAttempts;
- private IFingerprintDaemon mDaemon;
- private final PowerManager mPowerManager;
- private final AlarmManager mAlarmManager;
- private final UserManager mUserManager;
-
private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -148,6 +141,26 @@
}
};
+ private final Runnable mResetClientState = new Runnable() {
+ @Override
+ public void run() {
+ // Warning: if we get here, the driver never confirmed our call to cancel the current
+ // operation (authenticate, enroll, remove, enumerate, etc), which is
+ // really bad. The result will be a 3-second delay in starting each new client.
+ // If you see this on a device, make certain the driver notifies with
+ // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel()
+ // once it has successfully switched to the IDLE state in the fingerprint HAL.
+ // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent
+ // in response to an actual cancel() call.
+ Slog.w(TAG, "Client "
+ + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
+ + " failed to respond to cancel, starting client "
+ + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
+ mCurrentClient = null;
+ startClient(mPendingClient, false);
+ }
+ };
+
public FingerprintService(Context context) {
super(context);
mContext = context;
@@ -203,64 +216,49 @@
// TODO: update fingerprint/name pairs
}
- protected void handleRemoved(long deviceId, int fingerId, int groupId) {
- final ClientMonitor client = mRemoveClient;
- if (fingerId != 0) {
- removeTemplateForUser(mUserIdForRemove, fingerId);
- } else {
- mUserIdForRemove = UserHandle.USER_NULL;
+ protected void handleError(long deviceId, int error) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onError(error)) {
+ removeClient(client);
}
- if (client != null && client.sendRemoved(fingerId, groupId)) {
+ if (DEBUG) Slog.v(TAG, "handleError(client="
+ + client != null ? client.getOwnerString() : "null" + ", error = " + error + ")");
+ // This is the magic code that starts the next client when the old client finishes.
+ if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ mHandler.removeCallbacks(mResetClientState);
+ if (mPendingClient != null) {
+ if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString());
+ startClient(mPendingClient, false);
+ mPendingClient = null;
+ }
+ }
+ }
+
+ protected void handleRemoved(long deviceId, int fingerId, int groupId) {
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onRemoved(fingerId, groupId)) {
removeClient(client);
}
}
- protected void handleError(long deviceId, int error) {
- if (mEnrollClient != null) {
- final IBinder token = mEnrollClient.token;
- if (mEnrollClient.sendError(error)) {
- stopEnrollment(token, false);
- }
- } else if (mAuthClient != null) {
- final IBinder token = mAuthClient.token;
- if (mAuthClient.sendError(error)) {
- stopAuthentication(token, false);
- }
- } else if (mRemoveClient != null) {
- if (mRemoveClient.sendError(error)) removeClient(mRemoveClient);
- }
- }
-
protected void handleAuthenticated(long deviceId, int fingerId, int groupId) {
- if (mAuthClient != null) {
- final IBinder token = mAuthClient.token;
- if (mAuthClient.sendAuthenticated(fingerId, groupId)) {
- stopAuthentication(token, false);
- removeClient(mAuthClient);
- }
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onAuthenticated(fingerId, groupId)) {
+ removeClient(client);
}
}
protected void handleAcquired(long deviceId, int acquiredInfo) {
- if (mEnrollClient != null) {
- if (mEnrollClient.sendAcquired(acquiredInfo)) {
- removeClient(mEnrollClient);
- }
- } else if (mAuthClient != null) {
- if (mAuthClient.sendAcquired(acquiredInfo)) {
- removeClient(mAuthClient);
- }
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onAcquired(acquiredInfo)) {
+ removeClient(client);
}
}
protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
- if (mEnrollClient != null) {
- if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
- if (remaining == 0) {
- addTemplateForUser(mEnrollClient, fingerId);
- removeClient(mEnrollClient);
- }
- }
+ ClientMonitor client = mCurrentClient;
+ if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) {
+ removeClient(client);
}
}
@@ -274,14 +272,16 @@
}
private void removeClient(ClientMonitor client) {
- if (client == null) return;
- client.destroy();
- if (client == mAuthClient) {
- mAuthClient = null;
- } else if (client == mEnrollClient) {
- mEnrollClient = null;
- } else if (client == mRemoveClient) {
- mRemoveClient = null;
+ if (client != null) {
+ client.destroy();
+ if (client != mCurrentClient && mCurrentClient != null) {
+ Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: "
+ + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null");
+ }
+ }
+ if (mCurrentClient != null) {
+ if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString());
+ mCurrentClient = null;
}
}
@@ -303,60 +303,6 @@
new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
}
- private void resetFailedAttempts() {
- if (DEBUG && inLockoutMode()) {
- Slog.v(TAG, "Reset fingerprint lockout");
- }
- mFailedAttempts = 0;
- // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might
- // still be pending; remove it.
- cancelLockoutReset();
- notifyLockoutResetMonitors();
- }
-
- private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
- mFailedAttempts++;
- if (inLockoutMode()) {
- // Failing multiple times will continue to push out the lockout time.
- scheduleLockoutReset();
- if (clientMonitor != null
- && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
- Slog.w(TAG, "Cannot send lockout message to client");
- }
- return true;
- }
- return false;
- }
-
- private void removeTemplateForUser(int userId, int fingerId) {
- mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, userId);
- }
-
- private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) {
- mFingerprintUtils.addFingerprintForUser(mContext, fingerId, clientMonitor.userId);
- }
-
- void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
- IFingerprintDaemon daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "enroll: no fingeprintd!");
- return;
- }
- stopPendingOperations(true);
- mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString());
- final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
- try {
- final int result = daemon.enroll(cryptoToken, groupId, timeout);
- if (result != 0) {
- Slog.w(TAG, "startEnroll failed, result=" + result);
- handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "startEnroll failed", e);
- }
- }
-
public long startPreEnroll(IBinder token) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
@@ -385,123 +331,52 @@
return 0;
}
- private void stopPendingOperations(boolean initiatedByClient) {
- if (mEnrollClient != null) {
- stopEnrollment(mEnrollClient.token, initiatedByClient);
- }
- if (mAuthClient != null) {
- stopAuthentication(mAuthClient.token, initiatedByClient);
- }
- // mRemoveClient is allowed to continue
- }
-
/**
- * Stop enrollment in progress and inform client if they initiated it.
- *
- * @param token token for client
- * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+ * Calls fingerprintd to switch states to the new task. If there's already a current task,
+ * it calls cancel() and sets mPendingClient to begin when the current task finishes
+ * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}).
+ * @param newClient the new client that wants to connect
+ * @param initiatedByClient true for authenticate, remove and enroll
*/
- void stopEnrollment(IBinder token, boolean initiatedByClient) {
- IFingerprintDaemon daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopEnrollment: no fingeprintd!");
- return;
- }
- final ClientMonitor client = mEnrollClient;
- if (client == null || client.token != token) return;
- if (initiatedByClient) {
- try {
- int result = daemon.cancelEnrollment();
- if (result != 0) {
- Slog.w(TAG, "startEnrollCancel failed, result = " + result);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "stopEnrollment failed", e);
- }
- client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
- }
- removeClient(mEnrollClient);
- }
-
- void startAuthentication(IBinder token, long opId, int realUserId, int groupId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted,
- String opPackageName) {
- IFingerprintDaemon daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "startAuthentication: no fingeprintd!");
- return;
- }
- stopPendingOperations(true);
- updateActiveGroup(groupId, opPackageName);
- mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
- if (inLockoutMode()) {
- Slog.v(TAG, "In lockout mode; disallowing authentication");
- if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
- Slog.w(TAG, "Cannot send timeout message to client");
- }
- mAuthClient = null;
- return;
- }
- try {
- final int result = daemon.authenticate(opId, groupId);
- if (result != 0) {
- Slog.w(TAG, "startAuthentication failed, result=" + result);
- handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "startAuthentication failed", e);
+ private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
+ ClientMonitor currentClient = mCurrentClient;
+ if (currentClient != null) {
+ if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());
+ currentClient.stop(initiatedByClient);
+ mPendingClient = newClient;
+ mHandler.removeCallbacks(mResetClientState);
+ mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
+ } else if (newClient != null) {
+ mCurrentClient = newClient;
+ if (DEBUG) Slog.v(TAG, "starting client "
+ + newClient.getClass().getSuperclass().getSimpleName()
+ + "(" + newClient.getOwnerString() + ")"
+ + ", initiatedByClient = " + initiatedByClient + ")");
+ newClient.start();
}
}
- /**
- * Stop authentication in progress and inform client if they initiated it.
- *
- * @param token token for client
- * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
- */
- void stopAuthentication(IBinder token, boolean initiatedByClient) {
- IFingerprintDaemon daemon = getFingerprintDaemon();
- if (daemon == null) {
- Slog.w(TAG, "stopAuthentication: no fingeprintd!");
- return;
- }
- final ClientMonitor client = mAuthClient;
- if (client == null || client.token != token) return;
- if (initiatedByClient) {
- try {
- int result = daemon.cancelAuthentication();
- if (result != 0) {
- Slog.w(TAG, "stopAuthentication failed, result=" + result);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "stopAuthentication failed", e);
- }
- client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
- }
- removeClient(mAuthClient);
- }
-
- void startRemove(IBinder token, int fingerId, int userId,
+ void startRemove(IBinder token, int fingerId, int userId, int groupId,
IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startRemove: no fingeprintd!");
return;
}
-
- stopPendingOperations(true);
- mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
- mUserIdForRemove = mCurrentUserId;
- // The fingerprint template ids will be removed when we get confirmation from the HAL
- try {
- final int result = daemon.remove(fingerId, userId);
- if (result != 0) {
- Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
- handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
+ receiver, userId, groupId, fingerId, restricted, token.toString()) {
+ @Override
+ public void notifyUserActivity() {
+ FingerprintService.this.userActivity();
}
- } catch (RemoteException e) {
- Slog.e(TAG, "startRemove failed", e);
- }
+
+ @Override
+ public IFingerprintDaemon getFingerprintDaemon() {
+ FingerprintService.this.getFingerprintDaemon();
+ return null;
+ }
+ };
+ startClient(client, true);
}
public List<Fingerprint> getEnrolledFingerprints(int userId) {
@@ -572,10 +447,9 @@
* @param foregroundOnly only allow this call while app is in the foreground
* @return true if caller can use fingerprint API
*/
- private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
+ private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly, int uid,
+ int pid) {
checkPermission(USE_FINGERPRINT);
- final int uid = Binder.getCallingUid();
- final int pid = Binder.getCallingPid();
if (isKeyguard(opPackageName)) {
return true; // Keyguard is always allowed
}
@@ -620,165 +494,83 @@
}
}
- private class ClientMonitor implements IBinder.DeathRecipient {
- IBinder token;
- IFingerprintServiceReceiver receiver;
- int userId;
- boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
- String owner;
+ private void startAuthentication(IBinder token, long opId, int realUserId, int groupId,
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted,
+ String opPackageName) {
+ updateActiveGroup(groupId, opPackageName);
- public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
- boolean restricted, String owner) {
- this.token = token;
- this.receiver = receiver;
- this.userId = userId;
- this.restricted = restricted;
- this.owner = owner; // name of the client that owns this - for debugging
- try {
- token.linkToDeath(this, 0);
- } catch (RemoteException e) {
- Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
- }
- }
+ if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
- public void destroy() {
- if (token != null) {
- try {
- token.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- // TODO: remove when duplicate call bug is found
- Slog.e(TAG, "destroy(): " + this + ":", new Exception("here"));
+ AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
+ receiver, realUserId, groupId, opId, restricted, opPackageName) {
+ @Override
+ public boolean handleFailedAttempt() {
+ mFailedAttempts++;
+ if (inLockoutMode()) {
+ // Failing multiple times will continue to push out the lockout time.
+ scheduleLockoutReset();
+ return true;
}
- token = null;
+ return false;
}
- receiver = null;
- }
- @Override
- public void binderDied() {
- token = null;
- removeClient(this);
- receiver = null;
- }
+ @Override
+ public void resetFailedAttempts() {
+ FingerprintService.this.resetFailedAttempts();
+ }
- @Override
- protected void finalize() throws Throwable {
- try {
- if (token != null) {
- if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
- removeClient(this);
- }
- } finally {
- super.finalize();
+ @Override
+ public void notifyUserActivity() {
+ FingerprintService.this.userActivity();
}
- }
- /*
- * @return true if we're done.
- */
- private boolean sendRemoved(int fingerId, int groupId) {
- if (receiver == null) return true; // client not listening
- try {
- receiver.onRemoved(mHalDeviceId, fingerId, groupId);
- return fingerId == 0;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify Removed:", e);
+ @Override
+ public IFingerprintDaemon getFingerprintDaemon() {
+ return FingerprintService.this.getFingerprintDaemon();
}
- return false;
- }
+ };
- /*
- * @return true if we're done.
- */
- private boolean sendEnrollResult(int fpId, int groupId, int remaining) {
- if (receiver == null) return true; // client not listening
- FingerprintUtils.vibrateFingerprintSuccess(getContext());
- MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_ENROLL);
- try {
- receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining);
- return remaining == 0;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify EnrollResult:", e);
- return true;
+ if (inLockoutMode()) {
+ Slog.v(TAG, "In lockout mode; disallowing authentication");
+ // Don't bother starting the client. Just send the error message.
+ if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
+ Slog.w(TAG, "Cannot send timeout message to client");
}
+ return;
}
+ startClient(client, true /* initiatedByClient */);
+ }
- /*
- * @return true if we're done.
- */
- private boolean sendAuthenticated(int fpId, int groupId) {
- boolean result = false;
- boolean authenticated = fpId != 0;
- if (receiver != null) {
- try {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_AUTH,
- authenticated);
- if (!authenticated) {
- receiver.onAuthenticationFailed(mHalDeviceId);
- } else {
- if (DEBUG) {
- Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner
- + ", id=" + fpId + ", gp=" + groupId + ")");
- }
- Fingerprint fp = !restricted ?
- new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
- receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify Authenticated:", e);
- result = true; // client failed
- }
- } else {
- result = true; // client not listening
- }
- if (fpId == 0) {
- if (receiver != null) {
- FingerprintUtils.vibrateFingerprintError(getContext());
- }
- result |= handleFailedAttempt(this);
- } else {
- if (receiver != null) {
- FingerprintUtils.vibrateFingerprintSuccess(getContext());
- }
- result |= true; // we have a valid fingerprint
- resetFailedAttempts();
- }
- return result;
- }
+ private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, int groupId,
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted,
+ String opPackageName) {
+ updateActiveGroup(groupId, opPackageName);
- /*
- * @return true if we're done.
- */
- private boolean sendAcquired(int acquiredInfo) {
- if (receiver == null) return true; // client not listening
- try {
- receiver.onAcquired(mHalDeviceId, acquiredInfo);
- return false; // acquisition continues...
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke sendAcquired:", e);
- return true; // client failed
- }
- finally {
- // Good scans will keep the device awake
- if (acquiredInfo == FINGERPRINT_ACQUIRED_GOOD) {
- userActivity();
- }
- }
- }
+ EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver,
+ userId, groupId, cryptoToken, restricted, opPackageName) {
- /*
- * @return true if we're done.
- */
- private boolean sendError(int error) {
- if (receiver != null) {
- try {
- receiver.onError(mHalDeviceId, error);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to invoke sendError:", e);
- }
+ @Override
+ public IFingerprintDaemon getFingerprintDaemon() {
+ return FingerprintService.this.getFingerprintDaemon();
}
- return true; // errors always terminate progress
+
+ @Override
+ public void notifyUserActivity() {
+ FingerprintService.this.userActivity();
+ }
+ };
+ startClient(client, true /* initiatedByClient */);
+ }
+
+ protected void resetFailedAttempts() {
+ if (DEBUG && inLockoutMode()) {
+ Slog.v(TAG, "Reset fingerprint lockout");
}
+ mFailedAttempts = 0;
+ // If we're asked to reset failed attempts externally (i.e. from Keyguard),
+ // the alarm might still be pending; remove it.
+ cancelLockoutReset();
+ notifyLockoutResetMonitors();
}
private class FingerprintServiceLockoutResetMonitor {
@@ -876,8 +668,6 @@
};
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- private static final String KEYGUARD_PACKAGE = "com.android.systemui";
-
@Override // Binder call
public long preEnroll(IBinder token) {
checkPermission(MANAGE_FINGERPRINT);
@@ -892,7 +682,8 @@
@Override // Binder call
public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
- final IFingerprintServiceReceiver receiver, final int flags) {
+ final IFingerprintServiceReceiver receiver, final int flags,
+ final String opPackageName) {
checkPermission(MANAGE_FINGERPRINT);
final int limit = mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
@@ -903,7 +694,6 @@
Slog.w(TAG, "Too many fingerprints registered");
return;
}
- final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length);
// Group ID is arbitrarily set to parent profile user ID. It just represents
// the default fingerprints for the user.
@@ -915,7 +705,8 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted);
+ startEnrollment(token, cryptoToken, userId, groupId, receiver, flags,
+ restricted, opPackageName);
}
});
}
@@ -932,7 +723,10 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- stopEnrollment(token, true);
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof EnrollClient && client.getToken() == token) {
+ client.stop(client.getToken() == token);
+ }
}
});
}
@@ -941,17 +735,18 @@
public void authenticate(final IBinder token, final long opId, final int groupId,
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
- if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
- if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
- return;
- }
final int realUserId = Binder.getCallingUid();
-
+ final int pid = Binder.getCallingPid();
final boolean restricted = isRestricted();
mHandler.post(new Runnable() {
@Override
public void run() {
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
+ if (!canUseFingerprint(opPackageName, true /* foregroundOnly */,
+ realUserId, pid)) {
+ if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
+ return;
+ }
startAuthentication(token, opId, realUserId, groupId, receiver,
flags, restricted, opPackageName);
}
@@ -959,14 +754,29 @@
}
@Override // Binder call
- public void cancelAuthentication(final IBinder token, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
- return;
- }
+ public void cancelAuthentication(final IBinder token, final String opPackageName) {
+ final int uid = Binder.getCallingUid();
+ final int pid = Binder.getCallingPid();
mHandler.post(new Runnable() {
@Override
public void run() {
- stopAuthentication(token, true);
+ if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid)) {
+ if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName);
+ } else {
+ ClientMonitor client = mCurrentClient;
+ if (client instanceof AuthenticationClient) {
+ if (client.getToken() == token) {
+ if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString());
+ client.stop(client.getToken() == token);
+ } else {
+ if (DEBUG) Slog.v(TAG, "can't stop client "
+ + client.getOwnerString() + " since tokens don't match");
+ }
+ } else if (client != null) {
+ if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client "
+ + client.getOwnerString());
+ }
+ }
}
});
}
@@ -987,10 +797,11 @@
final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
+ final int realUserId = Binder.getCallingUid();
mHandler.post(new Runnable() {
@Override
public void run() {
- startRemove(token, fingerId, groupId, receiver, restricted);
+ startRemove(token, fingerId, realUserId, groupId, receiver, restricted);
}
});
@@ -998,7 +809,8 @@
@Override // Binder call
public boolean isHardwareDetected(long deviceId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid())) {
return false;
}
return mHalDeviceId != 0;
@@ -1021,7 +833,8 @@
@Override // Binder call
public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid())) {
return Collections.emptyList();
}
if (!isCurrentUserOrProfile(userId)) {
@@ -1033,7 +846,8 @@
@Override // Binder call
public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
- if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
+ if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid())) {
return false;
}
@@ -1061,7 +875,7 @@
// The permission check should be restored once Android Keystore no longer invokes this
// method from inside app processes.
- return FingerprintService.this.getAuthenticatorId();
+ return FingerprintService.this.getAuthenticatorId(opPackageName);
}
@Override // Binder call
@@ -1154,6 +968,7 @@
}
daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
mCurrentUserId = userId;
+ mCurrentAuthenticatorId = daemon.getAuthenticatorId();
}
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveGroup():", e);
@@ -1204,14 +1019,12 @@
}
}
- public long getAuthenticatorId() {
- IFingerprintDaemon daemon = getFingerprintDaemon();
- if (daemon != null) {
- try {
- return daemon.getAuthenticatorId();
- } catch (RemoteException e) {
- Slog.e(TAG, "getAuthenticatorId failed", e);
- }
+ public long getAuthenticatorId(String opPackageName) {
+ if (canUseFingerprint(opPackageName, false /* foregroundOnly */,
+ Binder.getCallingUid(), Binder.getCallingPid())) {
+ return mCurrentAuthenticatorId;
+ } else {
+ Slog.w(TAG, "Client isn't current, returning authenticator_id=0");
}
return 0;
}
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
new file mode 100644
index 0000000..69a96e1
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2016 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.fingerprint;
+
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+/**
+ * A class to keep track of the remove state for a given client.
+ */
+public abstract class RemovalClient extends ClientMonitor {
+ private int mFingerId;
+ private int mUserIdForRemove;
+
+ public RemovalClient(Context context, long halDeviceId, IBinder token,
+ IFingerprintServiceReceiver receiver, int userId, int groupId, int fingerId,
+ boolean restricted, String owner) {
+ super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
+ mFingerId = fingerId;
+ mUserIdForRemove = userId;
+ }
+
+ @Override
+ public int start() {
+ IFingerprintDaemon daemon = getFingerprintDaemon();
+ // The fingerprint template ids will be removed when we get confirmation from the HAL
+ try {
+ final int result = daemon.remove(mFingerId, getUserId());
+ if (result != 0) {
+ Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
+ onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+ return result;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "startRemove failed", e);
+ }
+ return 0;
+ }
+
+ @Override
+ public int stop(boolean initiatedByClient) {
+ // We don't actually stop remove, but inform the client that the cancel operation succeeded
+ // so we can start the next operation.
+ if (initiatedByClient) {
+ onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+ }
+ return 0;
+ }
+
+ /*
+ * @return true if we're done.
+ */
+ private boolean sendRemoved(int fingerId, int groupId) {
+ IFingerprintServiceReceiver receiver = getReceiver();
+ if (receiver == null)
+ return true; // client not listening
+ try {
+ receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+ return fingerId == 0;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to notify Removed:", e);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onRemoved(int fingerId, int groupId) {
+ if (fingerId != 0) {
+ if (fingerId != mFingerId)
+ FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
+ mUserIdForRemove);
+ } else {
+ mUserIdForRemove = UserHandle.USER_NULL;
+ }
+ return sendRemoved(fingerId, getGroupId());
+ }
+
+ @Override
+ public boolean onEnrollResult(int fingerId, int groupId, int rem) {
+ if (DEBUG) Slog.w(TAG, "onEnrollResult() called for remove!");
+ return true; // Invalid for Remove
+ }
+
+ @Override
+ public boolean onAuthenticated(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onAuthenticated() called for remove!");
+ return true; // Invalid for Remove.
+ }
+
+ @Override
+ public boolean onEnumerationResult(int fingerId, int groupId) {
+ if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for remove!");
+ return false; // Invalid for Remove.
+ }
+
+
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index fed7e4b..e07d72f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1189,7 +1189,9 @@
@Override
public void binderDied() {
synchronized (mLock) {
- mRecordListenerRecord = null;
+ if (mRecordListenerRecord == this) {
+ mRecordListenerRecord = null;
+ }
}
}
}
@@ -1813,7 +1815,9 @@
@Override
public void binderDied() {
synchronized (mLock) {
- mInputChangeListenerRecord = null;
+ if (mInputChangeListenerRecord == this) {
+ mInputChangeListenerRecord = null;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1fb260d..dc81c65 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2315,24 +2315,29 @@
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
- scanDirTracedLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
- | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
+ scanDirTracedLI(vendorOverlayDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR
+ | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
- scanDirTracedLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(frameworkDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// Collected privileged system packages.
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
- scanDirTracedLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(privilegedAppDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
// Collect ordinary system packages.
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
- scanDirTracedLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(systemAppDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all vendor packages.
@@ -2342,12 +2347,14 @@
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
- scanDirTracedLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(vendorAppDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
- scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
+ scanDirTracedLI(oemAppDir, mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Prune any system packages that no longer exist.
@@ -2428,10 +2435,12 @@
SystemClock.uptimeMillis());
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
- scanDirTracedLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+ scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
+ | PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
- scanDirLI(mEphemeralInstallDir, PackageParser.PARSE_IS_EPHEMERAL,
+ scanDirLI(mEphemeralInstallDir, mDefParseFlags
+ | PackageParser.PARSE_IS_EPHEMERAL,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
@@ -2476,7 +2485,7 @@
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
- final int reparseFlags;
+ int reparseFlags = mDefParseFlags;
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
@@ -6501,7 +6510,7 @@
return true;
}
- private void scanDirTracedLI(File dir, int parseFlags, int scanFlags, long currentTime) {
+ private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");
try {
scanDirLI(dir, parseFlags, scanFlags, currentTime);
@@ -6510,7 +6519,7 @@
}
}
- private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
+ private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
@@ -6576,7 +6585,7 @@
}
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
- int parseFlags) throws PackageManagerException {
+ final int policyFlags) throws PackageManagerException {
if (ps != null
&& ps.codePath.equals(srcFile)
&& ps.timeStamp == srcFile.lastModified()
@@ -6605,7 +6614,7 @@
}
try {
- PackageParser.collectCertificates(pkg, parseFlags);
+ PackageParser.collectCertificates(pkg, policyFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -6615,8 +6624,8 @@
* Traces a package scan.
* @see #scanPackageLI(File, int, int, long, UserHandle)
*/
- private PackageParser.Package scanPackageTracedLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
+ private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
+ int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
try {
return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
@@ -6632,7 +6641,6 @@
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
- parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
@@ -6642,11 +6650,14 @@
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
@@ -6657,7 +6668,7 @@
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
- int parseFlags, int scanFlags, long currentTime, UserHandle user)
+ final int policyFlags, int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
// If the package has children and this is the first dive in the function
// we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
@@ -6673,20 +6684,20 @@
}
// Scan the parent
- PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, parseFlags,
+ PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPackage = pkg.childPackages.get(i);
- scanPackageInternalLI(childPackage, scanFile, parseFlags, scanFlags,
+ scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,
currentTime, user);
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
}
return scannedPkg;
@@ -6697,7 +6708,7 @@
* @throws PackageManagerException on a parse error.
*/
private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile,
- int parseFlags, int scanFlags, long currentTime, UserHandle user)
+ int policyFlags, int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
PackageSetting ps = null;
PackageSetting updatedPkg;
@@ -6724,7 +6735,7 @@
// may need to remove disabled child packages on the system partition
// or may need to not add child packages if the parent apk is updated
// on the data partition and no longer defines this child package.
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
+ if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a parent package for an updated system app and this system
// app got an OTA update which no longer defines some of the child packages
// we have to prune them from the disabled system packages.
@@ -6754,7 +6765,7 @@
boolean updatedPkgBetter = false;
// First check if this is a system package that may involve an update
- if (updatedPkg != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
+ if (updatedPkg != null && (policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
// If new package is not located in "/system/priv-app" (e.g. due to an OTA),
// it needs to drop FLAG_PRIVILEGED.
if (locationIsPrivileged(scanFile)) {
@@ -6836,17 +6847,17 @@
if (updatedPkg != null) {
// An updated system app will not have the PARSE_IS_SYSTEM flag set
// initially
- parseFlags |= PackageParser.PARSE_IS_SYSTEM;
+ policyFlags |= PackageParser.PARSE_IS_SYSTEM;
// An updated privileged app will not have the PARSE_IS_PRIVILEGED
// flag set initially
if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
- parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
+ policyFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
}
// Verify certificates against what was last scanned
- collectCertificatesLI(ps, pkg, scanFile, parseFlags);
+ collectCertificatesLI(ps, pkg, scanFile, policyFlags);
/*
* A new system app appeared, but we already had a non-system one of the
@@ -6854,7 +6865,7 @@
*/
boolean shouldHideSystemApp = false;
if (updatedPkg == null && ps != null
- && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
+ && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) {
/*
* Check to make sure the signatures match first. If they don't,
* wipe the installed application and its data.
@@ -6902,16 +6913,16 @@
// are kept in different files. (except for app in either system or
// vendor path).
// TODO grab this value from PackageSettings
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
- parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
+ policyFlags |= PackageParser.PARSE_FORWARD_LOCK;
}
}
// TODO: extend to support forward-locked splits
String resourcePath = null;
String baseResourcePath = null;
- if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
+ if ((policyFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resourcePath = ps.resourcePathString;
baseResourcePath = ps.resourcePathString;
@@ -6934,7 +6945,7 @@
pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
// Note that we invoke the following method only if we are about to unpack an application
- PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
+ PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user);
/*
@@ -7576,8 +7587,9 @@
return cpuAbiOverride;
}
- private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg, int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
+ final int policyFlags, int scanFlags, long currentTime, UserHandle user)
+ throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
// If the package has children and this is the first dive in the function
// we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
@@ -7595,12 +7607,12 @@
final PackageParser.Package scannedPkg;
try {
// Scan the parent
- scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags, currentTime, user);
+ scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags, currentTime, user);
// Scan the children
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
- scanPackageLI(childPkg, parseFlags,
+ scanPackageLI(childPkg, policyFlags,
scanFlags, currentTime, user);
}
} finally {
@@ -7608,17 +7620,17 @@
}
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
+ return scanPackageTracedLI(pkg, policyFlags, scanFlags, currentTime, user);
}
return scannedPkg;
}
- private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
+ private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
try {
- final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
+ final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
currentTime, user);
success = true;
return res;
@@ -7632,8 +7644,8 @@
}
}
- private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
- int scanFlags, long currentTime, UserHandle user)
+ private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
+ final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
final File scanFile = new File(pkg.codePath);
if (pkg.applicationInfo.getCodePath() == null ||
@@ -7643,14 +7655,36 @@
"Code and resource paths haven't been set correctly");
}
- if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+ // Apply policy
+ if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ if (pkg.applicationInfo.isDirectBootAware()) {
+ // we're direct boot aware; set for all components
+ for (PackageParser.Service s : pkg.services) {
+ s.info.encryptionAware = s.info.directBootAware = true;
+ }
+ for (PackageParser.Provider p : pkg.providers) {
+ p.info.encryptionAware = p.info.directBootAware = true;
+ }
+ for (PackageParser.Activity a : pkg.activities) {
+ a.info.encryptionAware = a.info.directBootAware = true;
+ }
+ for (PackageParser.Activity r : pkg.receivers) {
+ r.info.encryptionAware = r.info.directBootAware = true;
+ }
+ }
} else {
// Only allow system apps to be flagged as core apps.
pkg.coreApp = false;
+ // clear flags not applicable to regular apps
+ pkg.applicationInfo.privateFlags &=
+ ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
+ pkg.applicationInfo.privateFlags &=
+ ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
}
+ pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
- if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
+ if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
@@ -7699,7 +7733,7 @@
}
if (DEBUG_PACKAGE_SCANNING) {
- if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Scanning package " + pkg.packageName);
}
@@ -7774,7 +7808,7 @@
+ " for shared user failed");
}
if (DEBUG_PACKAGE_SCANNING) {
- if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
+ "): packages=" + suid.packages);
}
@@ -7820,6 +7854,7 @@
origPackage = null;
continue;
}
+ // TODO: Add case when shared user id is added [b/28144775]
} else {
if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+ pkg.packageName + " to old name " + origPackage.name);
@@ -7886,7 +7921,7 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this. We
@@ -7907,7 +7942,7 @@
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} else {
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
@@ -7925,7 +7960,7 @@
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
} catch (PackageManagerException e) {
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
throw e;
}
// The signature has changed, but this package is in the system
@@ -8114,7 +8149,7 @@
// Only privileged apps and updated privileged apps can add child packages.
if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
- if ((parseFlags & PARSE_IS_PRIVILEGED) == 0) {
+ if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) {
throw new PackageManagerException("Only privileged apps and updated "
+ "privileged apps can add child packages. Ignoring package "
+ pkg.packageName);
@@ -8240,7 +8275,7 @@
} else if (pkgSetting.firstInstallTime == 0) {
// We need *something*. Take time time stamp of the file.
pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
- } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ } else if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
if (scanFileTime != pkgSetting.timeStamp) {
// A package on the system image has changed; consider this
// to be an update.
@@ -8283,7 +8318,7 @@
p.info.authority = p.info.authority + ";" + names[j];
}
if (DEBUG_PACKAGE_SCANNING) {
- if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Registered content provider: " + names[j]
+ ", className = " + p.info.name + ", isSyncable = "
+ p.info.isSyncable);
@@ -8298,7 +8333,7 @@
}
}
}
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8318,7 +8353,7 @@
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
s.info.processName, pkg.applicationInfo.uid);
mServices.addService(s);
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8338,7 +8373,7 @@
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mReceivers.addActivity(a, "receiver");
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8358,7 +8393,7 @@
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
a.info.processName, pkg.applicationInfo.uid);
mActivities.addActivity(a, "activity");
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8378,7 +8413,7 @@
PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name);
if (cur == null) {
mPermissionGroups.put(pg.info.name, pg);
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8390,7 +8425,7 @@
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName + " ignored: original from "
+ cur.info.packageName);
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8469,7 +8504,7 @@
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8488,7 +8523,7 @@
+ p.info.packageName + " ignored: original from "
+ bp.sourcePackage);
}
- } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ } else if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8523,7 +8558,7 @@
// need other information about the application, like the ABI and what not ?
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -13538,8 +13573,8 @@
/*
* Install a non-existing package.
*/
- private void installNewPackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags,
- UserHandle user, String installerPackageName, String volumeUuid,
+ private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags,
+ int scanFlags, UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
@@ -13568,7 +13603,7 @@
}
try {
- PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
+ PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, null, res, user);
@@ -13625,9 +13660,9 @@
return false;
}
- private void replacePackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags,
+ private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
UserHandle user, String installerPackageName, PackageInstalledInfo res) {
- final boolean isEphemeral = (parseFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
+ final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
@@ -13715,10 +13750,18 @@
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
- replaceSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
+ // Set the system/privileged flags as needed
+ final boolean privileged =
+ (oldPackage.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ final int systemPolicyFlags = policyFlags
+ | PackageParser.PARSE_IS_SYSTEM
+ | (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0);
+
+ replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags,
user, allUsers, installerPackageName, res);
} else {
- replaceNonSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
+ replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags,
user, allUsers, installerPackageName, res);
}
}
@@ -13733,7 +13776,7 @@
}
private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
- PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
+ PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
+ deletedPackage);
@@ -13775,7 +13818,7 @@
clearAppProfilesLIF(pkg);
try {
- final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
+ final PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
@@ -13872,20 +13915,13 @@
}
private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
- PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
+ PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user,
int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + deletedPackage);
final boolean disabledSystem;
- // Set the system/privileged flags as needed
- parseFlags |= PackageParser.PARSE_IS_SYSTEM;
- if ((deletedPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- != 0) {
- parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
- }
-
// Remove existing system package
removePackageLI(deletedPackage, true);
@@ -13914,7 +13950,7 @@
PackageParser.Package newPackage = null;
try {
// Add the package to the internal data structures
- newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
+ newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, 0, user);
// Set the update and install times
PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras;
@@ -13967,7 +14003,7 @@
}
// Add back the old system package
try {
- scanPackageTracedLI(deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
+ scanPackageTracedLI(deletedPackage, policyFlags, SCAN_UPDATE_SIGNATURE, 0, user);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
}
@@ -15296,7 +15332,10 @@
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
- int parseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM;
+ int parseFlags = mDefParseFlags
+ | PackageParser.PARSE_MUST_BE_APK
+ | PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR;
if (locationIsPrivileged(disabledPs.codePath)) {
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ac6510a..0ac5c1f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -907,6 +907,16 @@
}
}
+ public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) {
+ final File packagePath = new File(getUserBitmapFilePath(userId), packageName);
+ if (!packagePath.isDirectory()) {
+ return;
+ }
+ if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) {
+ Slog.w(TAG, "Unable to remove directory " + packagePath);
+ }
+ }
+
@VisibleForTesting
static class FileOutputStreamWithPath extends FileOutputStream {
private final File mFile;
@@ -1572,7 +1582,7 @@
// First, remove the package from the package list (if the package is a publisher).
if (packageUserId == owningUserId) {
- if (mUser.removePackage(packageName) != null) {
+ if (mUser.removePackage(this, packageName) != null) {
doNotify = true;
}
}
@@ -2084,11 +2094,11 @@
pw.println(mIconPersistFormat);
pw.print(" Icon quality: ");
pw.println(mIconPersistQuality);
- pw.print(" saveDelayMillis:");
+ pw.print(" saveDelayMillis: ");
pw.println(mSaveDelayMillis);
- pw.print(" resetInterval:");
+ pw.print(" resetInterval: ");
pw.println(mResetInterval);
- pw.print(" maxUpdatesPerInterval:");
+ pw.print(" maxUpdatesPerInterval: ");
pw.println(mMaxUpdatesPerInterval);
pw.print(" maxDynamicShortcuts:");
pw.println(mMaxDynamicShortcuts);
@@ -2416,7 +2426,6 @@
return mPackageManagerInternal;
}
- @VisibleForTesting
File getUserBitmapFilePath(@UserIdInt int userId) {
return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 593f607..0b8c3a2 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.ComponentName;
+import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.Slog;
@@ -29,6 +30,7 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -103,8 +105,12 @@
return mPackages;
}
- public ShortcutPackage removePackage(@NonNull String packageName) {
- return mPackages.remove(packageName);
+ public ShortcutPackage removePackage(@NonNull ShortcutService s, @NonNull String packageName) {
+ final ShortcutPackage removed = mPackages.remove(packageName);
+
+ s.cleanupBitmapsForPackage(mUserId, packageName);
+
+ return removed;
}
public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() {
@@ -279,18 +285,51 @@
pw.print(mUserId);
pw.println();
+ prefix += prefix + " ";
+
pw.print(prefix);
- pw.print(" ");
pw.print("Default launcher: ");
pw.print(mLauncherComponent);
pw.println();
for (int i = 0; i < mLaunchers.size(); i++) {
- mLaunchers.valueAt(i).dump(s, pw, prefix + " ");
+ mLaunchers.valueAt(i).dump(s, pw, prefix);
}
for (int i = 0; i < mPackages.size(); i++) {
- mPackages.valueAt(i).dump(s, pw, prefix + " ");
+ mPackages.valueAt(i).dump(s, pw, prefix);
}
+
+ pw.println();
+ pw.print(prefix);
+ pw.println("Bitmap directories: ");
+ dumpDirectorySize(s, pw, prefix + " ", s.getUserBitmapFilePath(mUserId));
+ }
+
+ private void dumpDirectorySize(@NonNull ShortcutService s, @NonNull PrintWriter pw,
+ @NonNull String prefix, File path) {
+ int numFiles = 0;
+ long size = 0;
+ final File[] children = path.listFiles();
+ if (children != null) {
+ for (File child : path.listFiles()) {
+ if (child.isFile()) {
+ numFiles++;
+ size += child.length();
+ } else if (child.isDirectory()) {
+ dumpDirectorySize(s, pw, prefix + " ", child);
+ }
+ }
+ }
+ pw.print(prefix);
+ pw.print("Path: ");
+ pw.print(path.getName());
+ pw.print("/ has ");
+ pw.print(numFiles);
+ pw.print(" files, size=");
+ pw.print(size);
+ pw.print(" (");
+ pw.print(Formatter.formatFileSize(s.mContext, size));
+ pw.println(")");
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 60ea254..9b918f3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -17,6 +17,9 @@
package com.android.server.pm;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,10 +30,12 @@
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
@@ -693,6 +698,37 @@
}
@Override
+ public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) {
+ if (mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userHandle)
+ || !mLockPatternUtils.isSecure(userHandle)
+ || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
+ // if the user is already unlocked, no need to show a profile challenge
+ setQuietModeEnabled(userHandle, false);
+ return true;
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // otherwise, we show a profile challenge to trigger decryption of the user
+ final KeyguardManager km = (KeyguardManager) mContext.getSystemService(
+ Context.KEYGUARD_SERVICE);
+ final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
+ userHandle);
+ if (unlockIntent == null) {
+ return false;
+ }
+ if (target != null) {
+ unlockIntent.putExtra(Intent.EXTRA_INTENT, target);
+ }
+ unlockIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ mContext.startActivity(unlockIntent);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return false;
+ }
+
+ @Override
public void setUserEnabled(int userId) {
checkManageUsersPermission("enable user");
synchronized (mPackagesLock) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f6f401a..8f259db 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4754,7 +4754,7 @@
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw()
- && !win.getGivenInsetsPendingLw()) {
+ && win.isDisplayedLw() && !win.getGivenInsetsPendingLw()) {
setLastInputMethodWindowLw(null, null);
offsetInputMethodWindowLw(win);
}
@@ -7190,10 +7190,6 @@
tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
}
- if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
- tmpVisibility |= StatusBarManager.DISABLE_RECENT;
- }
-
final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 9614417..95923fe 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -26,7 +26,7 @@
void buzzBeepBlinked();
void notificationLightPulse(int argb, int onMillis, int offMillis);
void notificationLightOff();
- void showScreenPinningRequest();
+ void showScreenPinningRequest(int taskId);
void showAssistDisclosure();
void startAssist(Bundle args);
void onCameraLaunchGestureDetected(int source);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index dbbaa5e..e71bdb8 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -153,10 +153,10 @@
}
@Override
- public void showScreenPinningRequest() {
+ public void showScreenPinningRequest(int taskId) {
if (mBar != null) {
try {
- mBar.showScreenPinningRequest();
+ mBar.showScreenPinningRequest(taskId);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 3c84fc2..728e244 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -26,6 +26,7 @@
import android.Manifest;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
import android.app.trust.ITrustManager;
@@ -318,6 +319,12 @@
synchronized (mDeviceLockedForUser) {
mDeviceLockedForUser.put(userId, locked);
}
+ if (locked) {
+ try {
+ ActivityManagerNative.getDefault().notifyLockedProfile(userId);
+ } catch (RemoteException e) {
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 10e30ed..91b6914 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -982,6 +982,7 @@
wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
final WallpaperData fallback = new WallpaperData(wallpaper.userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ ensureSaneWallpaperData(fallback);
bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
mWaitingForUnlock = true;
}
@@ -1773,12 +1774,14 @@
wallpaper = new WallpaperData(userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, wallpaper);
+ ensureSaneWallpaperData(wallpaper);
} else {
// sanity fallback: we're in bad shape, but establishing a known
// valid system+lock WallpaperData will keep us from dying.
Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
mWallpaperMap.put(userId, wallpaper);
+ ensureSaneWallpaperData(wallpaper);
}
}
}
@@ -1871,6 +1874,8 @@
wallpaper.cropHint.set(0, 0, 0, 0);
wallpaper.padding.set(0, 0, 0, 0);
wallpaper.name = "";
+
+ mLockWallpaperMap.remove(userId);
} else {
if (wallpaper.wallpaperId <= 0) {
wallpaper.wallpaperId = makeWallpaperIdLocked();
@@ -1881,6 +1886,14 @@
}
}
+ ensureSaneWallpaperData(wallpaper);
+ WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
+ if (lockWallpaper != null) {
+ ensureSaneWallpaperData(lockWallpaper);
+ }
+ }
+
+ private void ensureSaneWallpaperData(WallpaperData wallpaper) {
// We always want to have some reasonable width hint.
int baseSize = getMaximumSizeDimension();
if (wallpaper.width < baseSize) {
@@ -2072,11 +2085,11 @@
}
synchronized (mLock) {
- pw.println("Current Wallpaper Service state:");
+ pw.println("System wallpaper state:");
for (int i = 0; i < mWallpaperMap.size(); i++) {
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
pw.print(" User "); pw.print(wallpaper.userId);
- pw.print(": id="); pw.println(wallpaper.wallpaperId);
+ pw.print(": id="); pw.println(wallpaper.wallpaperId);
pw.print(" mWidth=");
pw.print(wallpaper.width);
pw.print(" mHeight=");
@@ -2104,6 +2117,18 @@
pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
}
}
+ pw.println("Lock wallpaper state:");
+ for (int i = 0; i < mLockWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
+ pw.print(" User "); pw.print(wallpaper.userId);
+ pw.print(": id="); pw.println(wallpaper.wallpaperId);
+ pw.print(" mWidth="); pw.print(wallpaper.width);
+ pw.print(" mHeight="); pw.println(wallpaper.height);
+ pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
+ pw.print(" mPadding="); pw.println(wallpaper.padding);
+ pw.print(" mName="); pw.println(wallpaper.name);
+ }
+
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 4ec297e..545b9db 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -499,7 +499,7 @@
+ " with replacing child windows.");
for (int i = allAppWindows.size() - 1; i >= 0; i--) {
final WindowState w = allAppWindows.get(i);
- if (w.isChildWindow()) {
+ if (w.shouldBeReplacedWithChildren()) {
w.setReplacing(false /* animate */);
}
}
@@ -539,8 +539,9 @@
for (int i = allAppWindows.size() - 1; i >= 0; i--) {
WindowState candidate = allAppWindows.get(i);
if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
- candidate.getWindowTag().equals(w.getWindowTag().toString())) {
+ candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
candidate.mReplacingWindow = w;
+ w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
// if we got a replacement window, reset the timeout to give drawing more time
service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
@@ -575,6 +576,9 @@
continue;
}
candidate.mWillReplaceWindow = false;
+ if (candidate.mReplacingWindow != null) {
+ candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
+ }
// Since the window already timed out, remove it immediately now.
// Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
// delays removal on certain conditions, which will leave the stale window in the
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 3ec02b9..c240d07 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -169,6 +169,10 @@
+ " dimLayerUser=" + dimLayerUser.toShortString()
+ " state.continueDimming=" + state.continueDimming
+ " state.dimLayer.isDimming=" + state.dimLayer.isDimming());
+ if (state.animator != null && state.animator.mWin.mWillReplaceWindow) {
+ return;
+ }
+
if (!state.continueDimming && state.dimLayer.isDimming()) {
state.animator = null;
dimLayerUser.getDimBounds(mTmpBounds);
@@ -303,7 +307,7 @@
applyDim(dimLayerUser, animator, true /* aboveApp */);
}
- private void applyDim(
+ void applyDim(
DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator, boolean aboveApp) {
if (dimLayerUser == null) {
Slog.e(TAG, "Trying to apply dim layer for: " + this
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ff537be..3bd7a96 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -38,8 +39,10 @@
import android.view.SurfaceControl;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import com.android.server.wm.DimLayer.DimLayerUser;
+import com.android.server.wm.WindowManagerService.H;
import java.util.ArrayList;
@@ -74,6 +77,13 @@
*/
private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
+ private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR =
+ new PathInterpolator(0.2f, 0f, 0.1f, 1f);
+
+ private static final long IME_ADJUST_ANIM_DURATION = 280;
+
+ private static final long IME_ADJUST_DRAWN_TIMEOUT = 200;
+
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private int mDividerWindowWidth;
@@ -95,11 +105,13 @@
private float mAnimationStart;
private float mAnimationTarget;
private long mAnimationDuration;
+ private boolean mAnimationStartDelayed;
private final Interpolator mMinimizedDockInterpolator;
private float mMaximizeMeetFraction;
private final Rect mTouchRegion = new Rect();
private boolean mAnimatingForIme;
private boolean mAdjustedForIme;
+ private WindowState mDelayedImeWin;
DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -186,10 +198,16 @@
return mLastVisibility;
}
- void setAdjustedForIme(boolean adjusted, boolean animate) {
+ void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
if (mAdjustedForIme != adjusted) {
- mAnimatingForIme = animate;
mAdjustedForIme = adjusted;
+ if (animate) {
+ startImeAdjustAnimation(adjusted, imeWin);
+ } else {
+
+ // Animation might be delayed, so only notify if we don't run an animation.
+ notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
+ }
}
}
@@ -283,12 +301,27 @@
mDockedStackListeners.finishBroadcast();
}
+ void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onAdjustedForImeChanged(adjustedForIme, animDuration);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
void registerDockedStackListener(IDockedStackListener listener) {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
notifyDockedStackExistsChanged(
mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */);
+ notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
+
}
void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
@@ -371,7 +404,7 @@
return;
}
- mAnimatingForIme = false;
+ clearImeAdjustAnimation();
if (minimizedDock) {
if (animate) {
startAdjustAnimation(0f, 1f);
@@ -387,6 +420,17 @@
}
}
+ private void clearImeAdjustAnimation() {
+ final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack != null && stack.isAdjustedForIme()) {
+ stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+ }
+ }
+ mAnimatingForIme = false;
+ }
+
private void startAdjustAnimation(float from, float to) {
mAnimatingForMinimizedDockedStack = true;
mAnimationStarted = false;
@@ -394,6 +438,48 @@
mAnimationTarget = to;
}
+ private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
+ mAnimatingForIme = true;
+ mAnimationStarted = false;
+ mAnimationStart = adjusted ? 0 : 1;
+ mAnimationTarget = adjusted ? 1 : 0;
+
+ final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+ for (int i = stacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = stacks.get(i);
+ if (stack.isVisibleLocked() && stack.isAdjustedForIme()) {
+ stack.beginImeAdjustAnimation();
+ }
+ }
+
+ // We put all tasks into drag resizing mode - wait until all of them have completed the
+ // drag resizing switch.
+ if (!mService.mWaitingForDrawn.isEmpty()) {
+ mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
+ mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT,
+ IME_ADJUST_DRAWN_TIMEOUT);
+ mAnimationStartDelayed = true;
+ if (imeWin != null) {
+
+ // There might be an old window delaying the animation start - clear it.
+ if (mDelayedImeWin != null) {
+ mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ }
+ mDelayedImeWin = imeWin;
+ imeWin.mWinAnimator.startDelayingAnimationStart();
+ }
+ mService.mWaitingForDrawnCallback = () -> {
+ mAnimationStartDelayed = false;
+ if (mDelayedImeWin != null) {
+ mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
+ }
+ notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+ };
+ } else {
+ notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+ }
+ }
+
private void setMinimizedDockedStack(boolean minimized) {
final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
notifyDockedStackMinimizedChanged(minimized, 0);
@@ -413,39 +499,48 @@
if (mAnimatingForMinimizedDockedStack) {
return animateForMinimizedDockedStack(now);
} else if (mAnimatingForIme) {
- return animateForIme();
+ return animateForIme(now);
} else {
return false;
}
}
- private boolean animateForIme() {
- boolean updated = false;
- boolean animating = false;
-
+ private boolean animateForIme(long now) {
+ if (!mAnimationStarted || mAnimationStartDelayed) {
+ mAnimationStarted = true;
+ mAnimationStartTime = now;
+ mAnimationDuration = (long)
+ (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked());
+ }
+ float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
+ t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR)
+ .getInterpolation(t);
final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
+ boolean updated = false;
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
if (stack != null && stack.isAdjustedForIme()) {
- updated |= stack.updateAdjustForIme();
- animating |= stack.isAnimatingForIme();
- }
- }
-
- if (updated) {
- mService.mWindowPlacerLocked.performSurfacePlacement();
- }
-
- if (!animating) {
- mAnimatingForIme = false;
- for (int i = stacks.size() - 1; i >= 0; --i) {
- final TaskStack stack = stacks.get(i);
- if (stack != null) {
- stack.clearImeGoingAway();
+ if (t >= 1f && mAnimationTarget == 0f) {
+ stack.resetAdjustedForIme(true /* adjustBoundsNow */);
+ updated = true;
+ } else {
+ updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+ false /* force */);
+ }
+ if (t >= 1f) {
+ stack.endImeAdjustAnimation();
}
}
}
- return animating;
+ if (updated) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ if (t >= 1.0f) {
+ mAnimatingForIme = false;
+ return false;
+ } else {
+ return true;
+ }
}
private boolean animateForMinimizedDockedStack(long now) {
@@ -478,11 +573,15 @@
}
}
+ private float getInterpolatedAnimationValue(float t) {
+ return t * mAnimationTarget + (1 - t) * mAnimationStart;
+ }
+
/**
* Gets the amount how much to minimize a stack depending on the interpolated fraction t.
*/
private float getMinimizeAmount(TaskStack stack, float t) {
- final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
+ final float naturalAmount = getInterpolatedAnimationValue(t);
if (isAnimationMaximizing()) {
return adjustMaximizeAmount(stack, t, naturalAmount);
} else {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7b16dbe..46a8dff 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -27,6 +27,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import android.app.ActivityManager.StackId;
import android.content.pm.ActivityInfo;
@@ -456,6 +457,11 @@
/** Bounds of the task to be used for dimming, as well as touch related tests. */
@Override
public void getDimBounds(Rect out) {
+ final DisplayContent displayContent = mStack.getDisplayContent();
+ // It doesn't matter if we in particular are part of the resize, since we couldn't have
+ // a DimLayer anyway if we weren't visible.
+ final boolean dockedResizing = displayContent != null ?
+ displayContent.mDividerControllerLocked.isResizing() : false;
if (useCurrentBounds()) {
if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
return;
@@ -464,8 +470,16 @@
if (!mFullscreen) {
// When minimizing the docked stack when going home, we don't adjust the task bounds
// so we need to intersect the task bounds with the stack bounds here.
- mStack.getBounds(mTmpRect);
- mTmpRect.intersect(mBounds);
+ //
+ // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
+ // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
+ // should keep up with the divider.
+ if (dockedResizing) {
+ mStack.getBounds(out);
+ } else {
+ mStack.getBounds(mTmpRect);
+ mTmpRect.intersect(mBounds);
+ }
out.set(mTmpRect);
} else {
out.set(mBounds);
@@ -476,7 +490,7 @@
// The bounds has been adjusted to accommodate for a docked stack, but the docked stack
// is not currently visible. Go ahead a represent it as fullscreen to the rest of the
// system.
- mStack.getDisplayContent().getLogicalDisplayRect(out);
+ displayContent.getLogicalDisplayRect(out);
}
void setDragResizing(boolean dragResizing, int dragResizeMode) {
@@ -509,6 +523,22 @@
return mDragResizeMode;
}
+ /**
+ * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
+ * resizing state of the window has been changed.
+ */
+ void addWindowsWaitingForDrawnIfResizingChanged() {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ if (win.isDragResizeChanged()) {
+ mService.mWaitingForDrawn.add(win);
+ }
+ }
+ }
+ }
+
void updateDisplayInfo(final DisplayContent displayContent) {
if (displayContent == null) {
return;
@@ -561,7 +591,16 @@
// If we are not drag resizing, force recreating of a new surface so updating
// the content and positioning that surface will be in sync.
- if (!win.computeDragResizing()) {
+ //
+ // As we use this flag as a hint to freeze surface boundary updates,
+ // we'd like to only apply this to TYPE_BASE_APPLICATION,
+ // windows of TYPE_APPLICATION like dialogs, could appear
+ // to not be drag resizing while they resize, but we'd
+ // still like to manipulate their frame to update crop, etc...
+ //
+ // Anyway we don't need to synchronize position and content updates for these
+ // windows since they aren't at the base layer and could be moved around anyway.
+ if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION) {
win.mResizedWhileNotDragResizing = true;
}
}
@@ -619,6 +658,16 @@
return false;
}
+ boolean isVisible() {
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken appToken = mAppTokens.get(i);
+ if (appToken.isVisible()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
boolean inHomeStack() {
return mStack != null && mStack.mStackId == HOME_STACK_ID;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7074a83..c322cd8 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,6 +26,7 @@
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
@@ -40,6 +41,7 @@
import android.util.SparseArray;
import android.view.DisplayInfo;
import android.view.Surface;
+import android.view.animation.PathInterpolator;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
@@ -52,14 +54,6 @@
public class TaskStack implements DimLayer.DimLayerUser,
BoundsAnimationController.AnimateBoundsUser {
- // If the stack should be resized to fullscreen.
- private static final boolean FULLSCREEN = true;
-
- // When we have a top-bottom split screen, we shift the bottom stack up to accommodate
- // the IME window. The static flag below controls whether to run animation when the
- // IME window goes away.
- private static final boolean ANIMATE_IME_GOING_AWAY = false;
-
/** Unique identifier */
final int mStackId;
@@ -83,6 +77,12 @@
/** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
private final Rect mAdjustedBounds = new Rect();
+ /**
+ * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
+ * represent the state when the animation has ended.
+ */
+ private final Rect mFullyAdjustedImeBounds = new Rect();
+
/** Whether mBounds is fullscreen */
private boolean mFullscreen = true;
@@ -118,6 +118,7 @@
private boolean mImeGoingAway;
private WindowState mImeWin;
private float mMinimizeAmount;
+ private float mAdjustImeAmount;
private final int mDockedStackMinimizeThickness;
// If this is true, the task will be down or upscaled
@@ -211,21 +212,26 @@
* the normal task bounds.
*
* @param bounds The adjusted bounds.
- * @param keepInsets Whether to keep the insets from the original bounds or to calculate new
- * ones depending on the adjusted bounds.
- * @return true if the adjusted bounds has changed.
*/
- private boolean setAdjustedBounds(Rect bounds, boolean keepInsets) {
- if (mAdjustedBounds.equals(bounds)) {
- return false;
+ private void setAdjustedBounds(Rect bounds) {
+ if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
+ return;
}
mAdjustedBounds.set(bounds);
final boolean adjusted = !mAdjustedBounds.isEmpty();
- alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
- adjusted && keepInsets ? mBounds : null);
+ Rect insetBounds = null;
+ if (adjusted && isAdjustedForMinimizedDock()) {
+ insetBounds = mBounds;
+ } else if (adjusted && isAdjustedForIme()) {
+ if (mImeGoingAway) {
+ insetBounds = mBounds;
+ } else {
+ insetBounds = mFullyAdjustedImeBounds;
+ }
+ }
+ alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
mDisplayContent.layoutNeeded = true;
- return true;
}
private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
@@ -828,17 +834,18 @@
* @param imeWin The IME window.
*/
void setAdjustedForIme(WindowState imeWin) {
- mAdjustedForIme = true;
mImeWin = imeWin;
mImeGoingAway = false;
+ if (!mAdjustedForIme) {
+ mAdjustedForIme = true;
+ mAdjustImeAmount = 0f;
+ updateAdjustForIme(0f, true /* force */);
+ }
}
boolean isAdjustedForIme() {
return mAdjustedForIme || mImeGoingAway;
}
- void clearImeGoingAway() {
- mImeGoingAway = false;
- }
boolean isAnimatingForIme() {
return mImeWin != null && mImeWin.isAnimatingLw();
@@ -852,16 +859,14 @@
*
* @return true if a traversal should be performed after the adjustment.
*/
- boolean updateAdjustForIme() {
- boolean stopped = false;
- if (mImeGoingAway && (!ANIMATE_IME_GOING_AWAY || !isAnimatingForIme())) {
- mImeWin = null;
- mAdjustedForIme = false;
- stopped = true;
+ boolean updateAdjustForIme(float adjustAmount, boolean force) {
+ if (adjustAmount != mAdjustImeAmount || force) {
+ mAdjustImeAmount = adjustAmount;
+ updateAdjustedBounds();
+ return isVisibleForUserLocked();
+ } else {
+ return false;
}
- // Make sure to run a traversal when the animation stops so that the stack
- // is moved to its final position.
- return updateAdjustedBounds() || stopped;
}
/**
@@ -875,6 +880,7 @@
mImeWin = null;
mAdjustedForIme = false;
mImeGoingAway = false;
+ mAdjustImeAmount = 0f;
updateAdjustedBounds();
} else {
mImeGoingAway |= mAdjustedForIme;
@@ -901,10 +907,32 @@
return mMinimizeAmount != 0f;
}
+ /**
+ * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
+ * to the list of to be drawn windows the service is waiting for.
+ */
+ void beginImeAdjustAnimation() {
+ for (int j = mTasks.size() - 1; j >= 0; j--) {
+ final Task task = mTasks.get(j);
+ if (task.isVisibleForUser()) {
+ task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+ task.addWindowsWaitingForDrawnIfResizingChanged();
+ }
+ }
+ }
+
+ /**
+ * Resets the resizing state of all windows.
+ */
+ void endImeAdjustAnimation() {
+ for (int j = mTasks.size() - 1; j >= 0; j--) {
+ mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+ }
+ }
+
private boolean adjustForIME(final WindowState imeWin) {
final int dockedSide = getDockSide();
final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
- final Rect adjustedBounds = mTmpAdjustedBounds;
if (imeWin == null || !dockedTopOrBottom) {
return false;
}
@@ -917,41 +945,37 @@
contentBounds.set(displayContentRect);
int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
- // if IME window is animating, get its actual vertical shown position (but no smaller than
- // the final target vertical position)
- if (imeWin.isAnimatingLw()) {
- imeTop = Math.max(imeTop, imeWin.getShownPositionLw().y);
- }
imeTop += imeWin.getGivenContentInsetsLw().top;
if (contentBounds.bottom > imeTop) {
contentBounds.bottom = imeTop;
}
- // If content bounds not changing, nothing to do.
- if (mLastContentBounds.equals(contentBounds)) {
- return true;
- }
-
- // Content bounds changed, need to apply adjustments depending on dock sides.
mLastContentBounds.set(contentBounds);
- adjustedBounds.set(mBounds);
final int yOffset = displayContentRect.bottom - contentBounds.bottom;
if (dockedSide == DOCKED_TOP) {
// If this stack is docked on top, we make it smaller so the bottom stack is not
// occluded by IME. We shift its bottom up by the height of the IME (capped by
// the display content rect). Note that we don't change the task bounds.
- adjustedBounds.bottom = Math.max(
- adjustedBounds.bottom - yOffset, displayContentRect.top);
+ int bottom = Math.max(
+ mBounds.bottom - yOffset, displayContentRect.top);
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.bottom =
+ (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
+ mFullyAdjustedImeBounds.set(mBounds);
} else {
// If this stack is docked on bottom, we shift it up so that it's not occluded by
// IME. We try to move it up by the height of the IME window (although the best
// we could do is to make the top stack fully collapsed).
final int dividerWidth = getDisplayContent().mDividerControllerLocked
.getContentWidth();
- adjustedBounds.top = Math.max(
- adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
- adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+ int top = Math.max(mBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.top =
+ (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top);
+ mFullyAdjustedImeBounds.set(mBounds);
+ mFullyAdjustedImeBounds.top = top;
+ mFullyAdjustedImeBounds.bottom = top + mBounds.height();
}
return true;
}
@@ -1007,7 +1031,7 @@
/**
* Updates the adjustment depending on it's current state.
*/
- boolean updateAdjustedBounds() {
+ void updateAdjustedBounds() {
boolean adjust = false;
if (mMinimizeAmount != 0f) {
adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
@@ -1018,7 +1042,7 @@
mTmpAdjustedBounds.setEmpty();
mLastContentBounds.setEmpty();
}
- return setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
+ setAdjustedBounds(mTmpAdjustedBounds);
}
boolean isAdjustedForMinimizedDockedStack() {
@@ -1030,6 +1054,9 @@
pw.println(prefix + "mDeferDetach=" + mDeferDetach);
pw.println(prefix + "mFullscreen=" + mFullscreen);
pw.println(prefix + "mBounds=" + mBounds.toShortString());
+ if (!mAdjustedBounds.isEmpty()) {
+ pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
+ }
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
mTasks.get(taskNdx).dump(prefix + " ", pw);
}
@@ -1158,7 +1185,7 @@
return mDragResizing;
}
- private void setDragResizingLocked(boolean resizing) {
+ void setDragResizingLocked(boolean resizing) {
if (mDragResizing == resizing) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57dc97a..a4238c1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -646,17 +646,24 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
+ if (uri == null) {
+ return;
+ }
+
if (mDisplayInversionEnabledUri.equals(uri)) {
updateCircularDisplayMaskIfNeeded();
} else {
@UpdateAnimationScaleMode
final int mode;
- if (uri.equals(mWindowAnimationScaleUri)) {
+ if (mWindowAnimationScaleUri.equals(uri)) {
mode = WINDOW_ANIMATION_SCALE;
- } else if (uri.equals(mTransitionAnimationScaleUri)) {
+ } else if (mTransitionAnimationScaleUri.equals(uri)) {
mode = TRANSITION_ANIMATION_SCALE;
- } else { // uri.equals(mAnimationDurationScaleUri)
+ } else if (mAnimationDurationScaleUri.equals(uri)) {
mode = ANIMATION_DURATION_SCALE;
+ } else {
+ // Ignoring unrecognized content changes
+ return;
}
Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
mH.sendMessage(m);
@@ -2595,7 +2602,7 @@
void repositionChild(Session session, IWindow client,
int left, int top, int right, int bottom,
- long deferTransactionUntilFrame, Rect outFrame) {
+ long frameNumber, Rect outFrame) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild");
long origId = Binder.clearCallingIdentity();
@@ -2631,10 +2638,8 @@
win.mWinAnimator.setSurfaceBoundariesLocked(false);
- if (deferTransactionUntilFrame > 0) {
- win.mWinAnimator.mSurfaceController.deferTransactionUntil(
- win.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
- deferTransactionUntilFrame);
+ if (frameNumber > 0) {
+ win.mWinAnimator.deferTransactionUntilParentFrame(frameNumber);
}
} finally {
@@ -5998,7 +6003,7 @@
@Override
public void run() {
Bitmap bm = screenshotApplicationsInner(null, Display.DEFAULT_DISPLAY, -1, -1,
- true, 1f);
+ true, 1f, Bitmap.Config.ARGB_8888);
try {
receiver.send(bm);
} catch (RemoteException e) {
@@ -6011,8 +6016,7 @@
/**
* Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
- * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
- * of the target image.
+ * In portrait mode, it grabs the full screenshot.
*
* @param displayId the Display to take a screenshot of.
* @param width the width of the target bitmap
@@ -6029,14 +6033,14 @@
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
return screenshotApplicationsInner(appToken, displayId, width, height, false,
- frameScale);
+ frameScale, Bitmap.Config.RGB_565);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height,
- boolean includeFullDisplay, float frameScale) {
+ boolean includeFullDisplay, float frameScale, Bitmap.Config config) {
final DisplayContent displayContent;
synchronized(mWindowMap) {
displayContent = getDisplayContentLocked(displayId);
@@ -6275,7 +6279,7 @@
// Create a copy of the screenshot that is immutable and backed in ashmem.
// This greatly reduces the overhead of passing the bitmap between processes.
- Bitmap ret = bm.createAshmemBitmap();
+ Bitmap ret = bm.createAshmemBitmap(config);
bm.recycle();
return ret;
}
@@ -7439,7 +7443,7 @@
}
}
- private void adjustForImeIfNeeded(final DisplayContent displayContent) {
+ void adjustForImeIfNeeded(final DisplayContent displayContent) {
final WindowState imeWin = mInputMethodWindow;
final TaskStack focusedStack =
mCurrentFocus != null ? mCurrentFocus.getStack() : null;
@@ -7455,14 +7459,14 @@
stack.setAdjustedForIme(imeWin);
}
}
- displayContent.mDividerControllerLocked.setAdjustedForIme(true, true);
+ displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin);
} else {
final ArrayList<TaskStack> stacks = displayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
stack.resetAdjustedForIme(!dockVisible);
}
- displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible);
+ displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8371cfe..bf69717 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -82,6 +82,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -444,6 +445,11 @@
// If not null, the window that will be used to replace the old one. This is being set when
// the window is added and unset when this window reports its first draw.
WindowState mReplacingWindow = null;
+ // For the new window in the replacement transition, if we have
+ // requested to replace without animation, then we should
+ // make sure we also don't apply an enter animation for
+ // the new window.
+ boolean mSkipEnterAnimationForSeamlessReplacement = false;
// Whether this window is being moved via the resize API
boolean mMovedByResize;
@@ -1552,7 +1558,7 @@
// If app died visible, apply a dim over the window to indicate that it's inactive
mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
} else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
- && mDisplayContent != null && !mAnimatingExit && isDisplayedLw()) {
+ && mDisplayContent != null && !mAnimatingExit && isVisibleUnchecked()) {
mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
}
}
@@ -1571,12 +1577,16 @@
}
for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) {
final WindowState win = mAppToken.allAppWindows.get(i);
- if (win.mWillReplaceWindow && win.mReplacingWindow == this) {
+ if (win.mWillReplaceWindow && win.mReplacingWindow == this && hasDrawnLw()) {
if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + win);
+ if (win.isDimming()) {
+ win.transferDimToReplacement();
+ }
win.mWillReplaceWindow = false;
win.mAnimateReplacingWindow = false;
win.mReplacingRemoveRequested = false;
win.mReplacingWindow = null;
+ mSkipEnterAnimationForSeamlessReplacement = false;
if (win.mAnimatingExit) {
mService.removeWindowInnerLocked(win);
}
@@ -2710,4 +2720,25 @@
}
return winY;
}
+
+ void transferDimToReplacement() {
+ final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+ if (dimLayerUser != null && mDisplayContent != null) {
+ mDisplayContent.mDimLayerController.applyDim(dimLayerUser,
+ mReplacingWindow.mWinAnimator,
+ (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? true : false);
+ }
+ }
+
+ // During activity relaunch due to resize, we sometimes use window replacement
+ // for only child windows (as the main window is handled by window preservation)
+ // and the big surface.
+ //
+ // Though windows of TYPE_APPLICATION (as opposed to TYPE_BASE_APPLICATION)
+ // are not children in the sense of an attached window, we also want to replace
+ // them at such phases, as they won't be covered by window preservation,
+ // and in general we expect them to return following relaunch.
+ boolean shouldBeReplacedWithChildren() {
+ return isChildWindow() || mAttrs.type == TYPE_APPLICATION;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0245513..6fcc8f9 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -21,7 +21,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -182,6 +183,8 @@
* window is first added or shown, cleared when the callback has been made. */
boolean mEnteringAnimation;
+ private boolean mAnimationStartDelayed;
+
boolean mKeyguardGoingAwayAnimation;
boolean mKeyguardGoingAwayWithWallpaper;
@@ -220,6 +223,10 @@
int mAttrType;
+ static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100;
+ long mDeferTransactionUntilFrame = -1;
+ long mDeferTransactionTime = -1;
+
private final Rect mTmpSize = new Rect();
WindowStateAnimator(final WindowState win) {
@@ -294,7 +301,7 @@
/** Is the window animating the DummyAnimation? */
boolean isDummyAnimation() {
return mAppAnimator != null
- && mAppAnimator.animation == AppWindowAnimator.sDummyAnimation;
+ && mAppAnimator.animation == sDummyAnimation;
}
/** Is this window currently set to animate or currently animating? */
@@ -318,8 +325,12 @@
if ((mAnimation == null) || !mLocalAnimating) {
return false;
}
+ currentTime = getAnimationFrameTime(mAnimation, currentTime);
mTransformation.clear();
final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
+ if (mAnimationStartDelayed && mAnimationIsEntrance) {
+ mTransformation.setAlpha(0f);
+ }
if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
+ ", xform=" + mTransformation);
return more;
@@ -1673,6 +1684,12 @@
}
void applyEnterAnimationLocked() {
+ // If we are the new part of a window replacement transition and we have requested
+ // not to animate, we instead want to make it seamless, so we don't want to apply
+ // an enter transition.
+ if (mWin.mSkipEnterAnimationForSeamlessReplacement) {
+ return;
+ }
final int transit;
if (mEnterAnimationPending) {
mEnterAnimationPending = false;
@@ -1755,7 +1772,9 @@
} else {
clearAnimation();
}
-
+ if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
+ mService.adjustForImeIfNeeded(mWin.mDisplayContent);
+ }
return mAnimation != null;
}
@@ -1834,6 +1853,9 @@
pw.print(" mDsDy="); pw.print(mDsDy);
pw.print(" mDtDy="); pw.println(mDtDy);
}
+ if (mAnimationStartDelayed) {
+ pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed);
+ }
}
@Override
@@ -1880,4 +1902,57 @@
mAnimDy = mWin.mLastFrame.top - top;
mAnimateMove = true;
}
+
+ void deferTransactionUntilParentFrame(long frameNumber) {
+ if (!mWin.isChildWindow()) {
+ return;
+ }
+ mDeferTransactionUntilFrame = frameNumber;
+ mDeferTransactionTime = System.currentTimeMillis();
+ mSurfaceController.deferTransactionUntil(
+ mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
+ frameNumber);
+ }
+
+ // Defer the current transaction to the frame number of the last saved transaction.
+ // We do this to avoid shooting through an unsynchronized transaction while something is
+ // pending. This is generally fine, as either we will get in on the synchronization,
+ // or SurfaceFlinger will see that the frame has already occured. The only
+ // potential problem is in frame number resets so we reset things with a timeout
+ // every so often to be careful.
+ void deferToPendingTransaction() {
+ if (mDeferTransactionUntilFrame < 0) {
+ return;
+ }
+ long time = System.currentTimeMillis();
+ if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) {
+ mDeferTransactionTime = -1;
+ mDeferTransactionUntilFrame = -1;
+ } else {
+ mSurfaceController.deferTransactionUntil(
+ mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(),
+ mDeferTransactionUntilFrame);
+ }
+ }
+
+ /**
+ * Sometimes we need to synchronize the first frame of animation with some external event.
+ * To achieve this, we prolong the start of the animation and keep producing the first frame of
+ * the animation.
+ */
+ private long getAnimationFrameTime(Animation animation, long currentTime) {
+ if (mAnimationStartDelayed) {
+ animation.setStartTime(currentTime);
+ return currentTime + 1;
+ }
+ return currentTime;
+ }
+
+ void startDelayingAnimationStart() {
+ mAnimationStartDelayed = true;
+ }
+
+ void endDelayingAnimationStart() {
+ mAnimationStartDelayed = false;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 04aa735..1e6c585 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -721,6 +721,10 @@
// Moved from updateWindowsAndWallpaperLocked().
if (w.mHasSurface) {
+ // If we have recently synchronized a previous transaction for this
+ // window ensure we don't push through an unsynchronized one now.
+ winAnimator.deferToPendingTransaction();
+
// Take care of the window being ready to display.
final boolean committed = winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index ce02a79..d20d5fa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -15,9 +15,36 @@
*/
package com.android.server.pm;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIcon;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconFile;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconResId;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIntents;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveTitle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllKeyFieldsOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveIntents;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveTitle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackNotReceived;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackReceived;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicAndPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.pfdToBitmap;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAll;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -27,7 +54,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.*;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -57,13 +83,11 @@
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.os.BaseBundle;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
@@ -71,7 +95,6 @@
import android.test.InstrumentationTestCase;
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -84,9 +107,6 @@
import com.android.server.pm.ShortcutService.ConfigConstants;
import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
import com.android.server.pm.ShortcutUser.PackageWithUser;
-import com.android.server.testutis.TestUtils;
-
-import libcore.io.IoUtils;
import org.junit.Assert;
import org.mockito.ArgumentCaptor;
@@ -98,8 +118,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -4018,24 +4036,33 @@
checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
}
+ private boolean bitmapDirectoryExists(String packageName, int userId) {
+ final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
+ return path.isDirectory();
+ }
+
public void testHandlePackageDelete() {
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ getTestContext().getResources(), R.drawable.black_32x32));
setCaller(CALLING_PACKAGE_1, USER_0);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(
+ makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
+ )));
setCaller(CALLING_PACKAGE_2, USER_0);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
setCaller(CALLING_PACKAGE_3, USER_0);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
setCaller(CALLING_PACKAGE_1, USER_10);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
setCaller(CALLING_PACKAGE_2, USER_10);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
setCaller(CALLING_PACKAGE_3, USER_10);
- assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+ assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
@@ -4044,6 +4071,13 @@
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
uninstallPackage(USER_0, CALLING_PACKAGE_1);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
@@ -4055,6 +4089,13 @@
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
uninstallPackage(USER_10, CALLING_PACKAGE_2);
mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
@@ -4066,6 +4107,13 @@
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
mInjectedPackages.remove(CALLING_PACKAGE_1);
mInjectedPackages.remove(CALLING_PACKAGE_3);
@@ -4078,6 +4126,13 @@
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
mService.handleUnlockUser(USER_10);
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
@@ -4086,6 +4141,13 @@
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+ assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+ assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
}
private void backupAndRestore() {
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8aa0e34..cfc5305 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -33,8 +33,6 @@
// From the top of ril.cpp
int RIL_ERRNO_INVALID_RESPONSE = -1;
- int MAX_INT = 0x7FFFFFFF;
-
// from RIL_Errno
int SUCCESS = 0;
int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 1a8197c..2ee1aef 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
@@ -31,13 +30,11 @@
import android.util.Log;
import android.util.SparseArray;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
/**
@@ -1143,7 +1140,6 @@
private final Object mListenerMapLock = new Object();
private AsyncChannel mAsyncChannel;
- private final CountDownLatch mConnected;
private final Handler mInternalHandler;
/**
@@ -1157,22 +1153,6 @@
* @hide
*/
public WifiScanner(Context context, IWifiScanner service, Looper looper) {
- this(context, service, looper, true);
- }
-
- /**
- * Create a new WifiScanner instance.
- *
- * @param context The application context.
- * @param service The IWifiScanner Binder interface
- * @param looper the Looper used to deliver callbacks
- * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
- * service is established.
- * @hide
- */
- @VisibleForTesting
- public WifiScanner(Context context, IWifiScanner service, Looper looper,
- boolean waitForConnection) {
mContext = context;
mService = service;
@@ -1188,17 +1168,12 @@
}
mAsyncChannel = new AsyncChannel();
- mConnected = new CountDownLatch(1);
mInternalHandler = new ServiceHandler(looper);
- mAsyncChannel.connect(mContext, mInternalHandler, messenger);
- if (waitForConnection) {
- try {
- mConnected.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "interrupted wait at init");
- }
- }
+ mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
+ // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
+ // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
}
private void validateChannel() {
@@ -1326,17 +1301,6 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
- } else {
- Log.e(TAG, "Failed to set up channel connection");
- // This will cause all further async API calls on the WifiManager
- // to fail and throw an exception
- mAsyncChannel = null;
- }
- mConnected.countDown();
- return;
case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
return;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED: