Merge "Import translations. DO NOT MERGE"
diff --git a/Android.mk b/Android.mk
index 1a6b8cc..20e9bee 100644
--- a/Android.mk
+++ b/Android.mk
@@ -288,7 +288,6 @@
core/java/com/android/internal/view/IInputMethodSession.aidl \
core/java/com/android/internal/view/IInputSessionCallback.aidl \
core/java/com/android/internal/widget/ILockSettings.aidl \
- core/java/com/android/internal/widget/ILockSettingsObserver.aidl \
core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
keystore/java/android/security/IKeyChainAliasCallback.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 28c2172..d660224 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -224,6 +224,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/inputflinger $(PRODUCT_OUT)/symbols/system/bin/inputflinger)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RsFountainFbo_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/telecomm/java/com/android/internal/telecomm)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/widget/ILockSettingsObserver.java)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 97426c3..bd7bca0 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -105,10 +105,6 @@
private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
new HashMap<Class, HashMap<String, Method>>();
- // This lock is used to ensure that only one thread is accessing the property maps
- // at a time.
- final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock();
-
// Used to pass single value to varargs parameter in setter invocation
final Object[] mTmpValueArray = new Object[1];
@@ -737,16 +733,19 @@
HashMap<Class, HashMap<String, Method>> propertyMapMap,
String prefix, Class valueType) {
Method setterOrGetter = null;
- try {
+ synchronized(propertyMapMap) {
// Have to lock property map prior to reading it, to guard against
// another thread putting something in there after we've checked it
// but before we've added an entry to it
- mPropertyMapLock.writeLock().lock();
HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
+ boolean wasInMap = false;
if (propertyMap != null) {
- setterOrGetter = propertyMap.get(mPropertyName);
+ wasInMap = propertyMap.containsKey(mPropertyName);
+ if (wasInMap) {
+ setterOrGetter = propertyMap.get(mPropertyName);
+ }
}
- if (setterOrGetter == null) {
+ if (!wasInMap) {
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
if (propertyMap == null) {
propertyMap = new HashMap<String, Method>();
@@ -754,8 +753,6 @@
}
propertyMap.put(mPropertyName, setterOrGetter);
}
- } finally {
- mPropertyMapLock.writeLock().unlock();
}
return setterOrGetter;
}
@@ -811,30 +808,33 @@
mProperty = null;
}
}
- Class targetClass = target.getClass();
- if (mSetter == null) {
- setupSetter(targetClass);
- }
- List<Keyframe> keyframes = mKeyframes.getKeyframes();
- int keyframeCount = keyframes == null ? 0 : keyframes.size();
- for (int i = 0; i < keyframeCount; i++) {
- Keyframe kf = keyframes.get(i);
- if (!kf.hasValue() || kf.valueWasSetOnStart()) {
- if (mGetter == null) {
- setupGetter(targetClass);
+ // We can't just say 'else' here because the catch statement sets mProperty to null.
+ if (mProperty == null) {
+ Class targetClass = target.getClass();
+ if (mSetter == null) {
+ setupSetter(targetClass);
+ }
+ List<Keyframe> keyframes = mKeyframes.getKeyframes();
+ int keyframeCount = keyframes == null ? 0 : keyframes.size();
+ for (int i = 0; i < keyframeCount; i++) {
+ Keyframe kf = keyframes.get(i);
+ if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (mGetter == null) {
- // Already logged the error - just return to avoid NPE
- return;
+ setupGetter(targetClass);
+ if (mGetter == null) {
+ // Already logged the error - just return to avoid NPE
+ return;
+ }
}
- }
- try {
- Object value = convertBack(mGetter.invoke(target));
- kf.setValue(value);
- kf.setValueWasSetOnStart(true);
- } catch (InvocationTargetException e) {
- Log.e("PropertyValuesHolder", e.toString());
- } catch (IllegalAccessException e) {
- Log.e("PropertyValuesHolder", e.toString());
+ try {
+ Object value = convertBack(mGetter.invoke(target));
+ kf.setValue(value);
+ kf.setValueWasSetOnStart(true);
+ } catch (InvocationTargetException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ } catch (IllegalAccessException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ }
}
}
}
@@ -1178,32 +1178,33 @@
return;
}
// Check new static hashmap<propName, int> for setter method
- try {
- mPropertyMapLock.writeLock().lock();
+ synchronized(sJNISetterPropertyMap) {
HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ boolean wasInMap = false;
if (propertyMap != null) {
- Long jniSetter = propertyMap.get(mPropertyName);
- if (jniSetter != null) {
- mJniSetter = jniSetter;
- }
- }
- if (mJniSetter == 0) {
- String methodName = getMethodName("set", mPropertyName);
- mJniSetter = nGetIntMethod(targetClass, methodName);
- if (mJniSetter != 0) {
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Long>();
- sJNISetterPropertyMap.put(targetClass, propertyMap);
+ wasInMap = propertyMap.containsKey(mPropertyName);
+ if (wasInMap) {
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
}
- propertyMap.put(mPropertyName, mJniSetter);
}
}
- } catch (NoSuchMethodError e) {
- // Couldn't find it via JNI - try reflection next. Probably means the method
- // doesn't exist, or the type is wrong. An error will be logged later if
- // reflection fails as well.
- } finally {
- mPropertyMapLock.writeLock().unlock();
+ if (!wasInMap) {
+ String methodName = getMethodName("set", mPropertyName);
+ try {
+ mJniSetter = nGetIntMethod(targetClass, methodName);
+ } catch (NoSuchMethodError e) {
+ // Couldn't find it via JNI - try reflection next. Probably means the method
+ // doesn't exist, or the type is wrong. An error will be logged later if
+ // reflection fails as well.
+ }
+ if (propertyMap == null) {
+ propertyMap = new HashMap<String, Long>();
+ sJNISetterPropertyMap.put(targetClass, propertyMap);
+ }
+ propertyMap.put(mPropertyName, mJniSetter);
+ }
}
if (mJniSetter == 0) {
// Couldn't find method through fast JNI approach - just use reflection
@@ -1315,32 +1316,33 @@
return;
}
// Check new static hashmap<propName, int> for setter method
- try {
- mPropertyMapLock.writeLock().lock();
+ synchronized (sJNISetterPropertyMap) {
HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ boolean wasInMap = false;
if (propertyMap != null) {
- Long jniSetter = propertyMap.get(mPropertyName);
- if (jniSetter != null) {
- mJniSetter = jniSetter;
- }
- }
- if (mJniSetter == 0) {
- String methodName = getMethodName("set", mPropertyName);
- mJniSetter = nGetFloatMethod(targetClass, methodName);
- if (mJniSetter != 0) {
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Long>();
- sJNISetterPropertyMap.put(targetClass, propertyMap);
+ wasInMap = propertyMap.containsKey(mPropertyName);
+ if (wasInMap) {
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
}
- propertyMap.put(mPropertyName, mJniSetter);
}
}
- } catch (NoSuchMethodError e) {
- // Couldn't find it via JNI - try reflection next. Probably means the method
- // doesn't exist, or the type is wrong. An error will be logged later if
- // reflection fails as well.
- } finally {
- mPropertyMapLock.writeLock().unlock();
+ if (!wasInMap) {
+ String methodName = getMethodName("set", mPropertyName);
+ try {
+ mJniSetter = nGetFloatMethod(targetClass, methodName);
+ } catch (NoSuchMethodError e) {
+ // Couldn't find it via JNI - try reflection next. Probably means the method
+ // doesn't exist, or the type is wrong. An error will be logged later if
+ // reflection fails as well.
+ }
+ if (propertyMap == null) {
+ propertyMap = new HashMap<String, Long>();
+ sJNISetterPropertyMap.put(targetClass, propertyMap);
+ }
+ propertyMap.put(mPropertyName, mJniSetter);
+ }
}
if (mJniSetter == 0) {
// Couldn't find method through fast JNI approach - just use reflection
@@ -1419,16 +1421,19 @@
if (mJniSetter != 0) {
return;
}
- try {
- mPropertyMapLock.writeLock().lock();
+ synchronized(sJNISetterPropertyMap) {
HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ boolean wasInMap = false;
if (propertyMap != null) {
- Long jniSetterLong = propertyMap.get(mPropertyName);
- if (jniSetterLong != null) {
- mJniSetter = jniSetterLong;
+ wasInMap = propertyMap.containsKey(mPropertyName);
+ if (wasInMap) {
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
+ }
}
}
- if (mJniSetter == 0) {
+ if (!wasInMap) {
String methodName = getMethodName("set", mPropertyName);
calculateValue(0f);
float[] values = (float[]) getAnimatedValue();
@@ -1437,19 +1442,20 @@
mJniSetter = nGetMultipleFloatMethod(targetClass, methodName, numParams);
} catch (NoSuchMethodError e) {
// try without the 'set' prefix
- mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName, numParams);
- }
- if (mJniSetter != 0) {
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Long>();
- sJNISetterPropertyMap.put(targetClass, propertyMap);
+ try {
+ mJniSetter = nGetMultipleFloatMethod(targetClass, mPropertyName,
+ numParams);
+ } catch (NoSuchMethodError e2) {
+ // just try reflection next
}
- propertyMap.put(mPropertyName, mJniSetter);
}
+ if (propertyMap == null) {
+ propertyMap = new HashMap<String, Long>();
+ sJNISetterPropertyMap.put(targetClass, propertyMap);
+ }
+ propertyMap.put(mPropertyName, mJniSetter);
}
- } finally {
- mPropertyMapLock.writeLock().unlock();
- }
+ }
}
}
@@ -1522,16 +1528,19 @@
if (mJniSetter != 0) {
return;
}
- try {
- mPropertyMapLock.writeLock().lock();
+ synchronized(sJNISetterPropertyMap) {
HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ boolean wasInMap = false;
if (propertyMap != null) {
- Long jniSetterLong = propertyMap.get(mPropertyName);
- if (jniSetterLong != null) {
- mJniSetter = jniSetterLong;
+ wasInMap = propertyMap.containsKey(mPropertyName);
+ if (wasInMap) {
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
+ }
}
}
- if (mJniSetter == 0) {
+ if (!wasInMap) {
String methodName = getMethodName("set", mPropertyName);
calculateValue(0f);
int[] values = (int[]) getAnimatedValue();
@@ -1540,18 +1549,19 @@
mJniSetter = nGetMultipleIntMethod(targetClass, methodName, numParams);
} catch (NoSuchMethodError e) {
// try without the 'set' prefix
- mJniSetter = nGetMultipleIntMethod(targetClass, mPropertyName, numParams);
- }
- if (mJniSetter != 0) {
- if (propertyMap == null) {
- propertyMap = new HashMap<String, Long>();
- sJNISetterPropertyMap.put(targetClass, propertyMap);
+ try {
+ mJniSetter = nGetMultipleIntMethod(targetClass, mPropertyName,
+ numParams);
+ } catch (NoSuchMethodError e2) {
+ // couldn't find it.
}
- propertyMap.put(mPropertyName, mJniSetter);
}
+ if (propertyMap == null) {
+ propertyMap = new HashMap<String, Long>();
+ sJNISetterPropertyMap.put(targetClass, propertyMap);
+ }
+ propertyMap.put(mPropertyName, mJniSetter);
}
- } finally {
- mPropertyMapLock.writeLock().unlock();
}
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 3ada9bb..21a9904 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -689,6 +689,20 @@
}
/**
+ * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block and retry if the
+ * zygote is unresponsive. This method is a no-op if a connection is already open.
+ *
+ * @hide
+ */
+ public static void establishZygoteConnectionForAbi(String abi) {
+ try {
+ openZygoteSocketIfNeeded(abi);
+ } catch (ZygoteStartFailedEx ex) {
+ throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
+ }
+ }
+
+ /**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry.
*/
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index c70841b..9501f92 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,8 +16,6 @@
package com.android.internal.widget;
-import com.android.internal.widget.ILockSettingsObserver;
-
/** {@hide} */
interface ILockSettings {
void setBoolean(in String key, in boolean value, in int userId);
@@ -34,6 +32,4 @@
boolean havePattern(int userId);
boolean havePassword(int userId);
void removeUser(int userId);
- void registerObserver(in ILockSettingsObserver observer);
- void unregisterObserver(in ILockSettingsObserver observer);
}
diff --git a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl b/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
deleted file mode 100644
index edf8f0e..0000000
--- a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2014 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.internal.widget;
-
-/** {@hide} */
-oneway interface ILockSettingsObserver {
- /**
- * Called when a lock setting has changed.
- *
- * Note: Impementations of this should do as little work as possible, because this may be
- * called synchronously while writing a setting.
- *
- * @param key the key of the setting that has changed or {@code null} if any may have changed.
- * @param userId the user whose setting has changed.
- */
- void onLockSettingChanged(in String key, in int userId);
-}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a4b8380..3ccced5 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -65,13 +65,6 @@
private static final boolean DEBUG = false;
/**
- * If true, LockPatternUtils will cache its values in-process. While this leads to faster reads,
- * it can cause problems because writes to to the settings are no longer synchronous
- * across all processes.
- */
- private static final boolean ENABLE_CLIENT_CACHE = false;
-
- /**
* The maximum number of incorrect attempts before the user is prevented
* from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
*/
@@ -216,11 +209,7 @@
if (mLockSettingsService == null) {
ILockSettings service = ILockSettings.Stub.asInterface(
ServiceManager.getService("lock_settings"));
- if (ENABLE_CLIENT_CACHE) {
- mLockSettingsService = LockPatternUtilsCache.getInstance(service);
- } else {
- mLockSettingsService = service;
- }
+ mLockSettingsService = service;
}
return mLockSettingsService;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtilsCache.java b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
deleted file mode 100644
index a9524ff..0000000
--- a/core/java/com/android/internal/widget/LockPatternUtilsCache.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2014 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.internal.widget;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.Log;
-
-/**
- * A decorator for {@link ILockSettings} that caches the key-value responses in memory.
- *
- * Specifically, the return values of {@link #getString(String, String, int)},
- * {@link #getLong(String, long, int)} and {@link #getBoolean(String, boolean, int)} are cached.
- */
-public class LockPatternUtilsCache implements ILockSettings {
-
- private static final String TAG = "LockPatternUtilsCache";
-
- public static final String HAS_LOCK_PATTERN_CACHE_KEY
- = "LockPatternUtils.Cache.HasLockPatternCacheKey";
- public static final String HAS_LOCK_PASSWORD_CACHE_KEY
- = "LockPatternUtils.Cache.HasLockPasswordCacheKey";
-
- private static LockPatternUtilsCache sInstance;
-
- private final ILockSettings mService;
-
- /** Only access when holding {@code mCache} lock. */
- private final ArrayMap<CacheKey, Object> mCache = new ArrayMap<>();
-
- /** Only access when holding {@link #mCache} lock. */
- private final CacheKey mCacheKey = new CacheKey();
-
-
- public static synchronized LockPatternUtilsCache getInstance(ILockSettings service) {
- if (sInstance == null) {
- sInstance = new LockPatternUtilsCache(service);
- }
- return sInstance;
- }
-
- // ILockSettings
-
- public LockPatternUtilsCache(ILockSettings service) {
- mService = service;
- try {
- service.registerObserver(mObserver);
- } catch (RemoteException e) {
- // Not safe to do caching without the observer. System process has probably died
- // anyway, so crashing here is fine.
- throw new RuntimeException(e);
- }
- }
-
- public void setBoolean(String key, boolean value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setBoolean(key, value, userId);
- putCache(key, userId, value);
- }
-
- public void setLong(String key, long value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setLong(key, value, userId);
- putCache(key, userId, value);
- }
-
- public void setString(String key, String value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setString(key, value, userId);
- putCache(key, userId, value);
- }
-
- public long getLong(String key, long defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof Long) {
- return (long) value;
- }
- long result = mService.getLong(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- public String getString(String key, String defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof String) {
- return (String) value;
- }
- String result = mService.getString(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.getBoolean(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- @Override
- public void setLockPattern(String pattern, int userId) throws RemoteException {
- invalidateCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
- mService.setLockPattern(pattern, userId);
- putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, pattern != null);
- }
-
- @Override
- public boolean checkPattern(String pattern, int userId) throws RemoteException {
- return mService.checkPattern(pattern, userId);
- }
-
- @Override
- public void setLockPassword(String password, int userId) throws RemoteException {
- invalidateCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
- mService.setLockPassword(password, userId);
- putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, password != null);
- }
-
- @Override
- public boolean checkPassword(String password, int userId) throws RemoteException {
- return mService.checkPassword(password, userId);
- }
-
- @Override
- public boolean checkVoldPassword(int userId) throws RemoteException {
- return mService.checkVoldPassword(userId);
- }
-
- @Override
- public boolean havePattern(int userId) throws RemoteException {
- Object value = peekCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.havePattern(userId);
- putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, result);
- return result;
- }
-
- @Override
- public boolean havePassword(int userId) throws RemoteException {
- Object value = peekCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.havePassword(userId);
- putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, result);
- return result;
- }
-
- @Override
- public void removeUser(int userId) throws RemoteException {
- mService.removeUser(userId);
- }
-
- @Override
- public void registerObserver(ILockSettingsObserver observer) throws RemoteException {
- mService.registerObserver(observer);
- }
-
- @Override
- public void unregisterObserver(ILockSettingsObserver observer) throws RemoteException {
- mService.unregisterObserver(observer);
- }
-
- @Override
- public IBinder asBinder() {
- return mService.asBinder();
- }
-
- // Caching
-
- private Object peekCache(String key, int userId) {
- if (!validateUserId(userId)) return null;
- synchronized (mCache) {
- // Safe to reuse mCacheKey, because it is not stored in the map.
- return mCache.get(mCacheKey.set(key, userId));
- }
- }
-
- private void putCache(String key, int userId, Object value) {
- if (!validateUserId(userId)) return;
- synchronized (mCache) {
- // Create a new key, because this will be stored in the map.
- mCache.put(new CacheKey().set(key, userId), value);
- }
- }
-
- private void invalidateCache(String key, int userId) {
- if (!validateUserId(userId)) return;
- synchronized (mCache) {
- if (key != null) {
- // Safe to reuse mCacheKey, because it is not stored in the map.
- mCache.remove(mCacheKey.set(key, userId));
- } else {
- mCache.clear();
- }
- }
- }
-
- private final ILockSettingsObserver mObserver = new ILockSettingsObserver.Stub() {
- @Override
- public void onLockSettingChanged(String key, int userId) throws RemoteException {
- invalidateCache(key, userId);
- }
- };
-
- private final boolean validateUserId(int userId) {
- if (userId < UserHandle.USER_OWNER) {
- Log.e(TAG, "User " + userId + " not supported: Must be a concrete user.");
- return false;
- }
- return true;
- }
-
- private static final class CacheKey {
- String key;
- int userId;
-
- public CacheKey set(String key, int userId) {
- this.key = key;
- this.userId = userId;
- return this;
- }
-
- public CacheKey copy() {
- return new CacheKey().set(key, userId);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof CacheKey))
- return false;
- CacheKey o = (CacheKey) obj;
- return userId == o.userId && key.equals(o.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode() ^ userId;
- }
- }
-}
diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml
index 60e4109..aaf7f15 100644
--- a/core/res/res/anim/app_starting_exit.xml
+++ b/core/res/res/anim/app_starting_exit.xml
@@ -18,8 +18,11 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:interpolator="@interpolator/decelerate_quad">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="160" />
-</set>
+<alpha
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:detachWallpaper="true"
+ android:interpolator="@interpolator/decelerate_quad"
+ android:fromAlpha="1.0"
+ android:toAlpha="0.0"
+ android:duration="160" />
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index e8afada..6f3c4d42 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -21,7 +21,7 @@
android:shareInterpolator="false"
android:startOffset="100">
- <translate android:fromYDelta="110%" android:toYDelta="0"
+ <translate android:fromYDelta="110%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
android:duration="300" />
diff --git a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
index ce974dc..660b662 100644
--- a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
+++ b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
@@ -23,7 +23,7 @@
android:interpolator="@interpolator/decelerate_quint"
android:duration="400"/>
- <translate android:fromYDelta="11%" android:toYDelta="0"
+ <translate android:fromYDelta="11%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
android:duration="300" />
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 864e119..6731366 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -26,6 +26,7 @@
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
+import android.graphics.Xfermode;
import android.util.MathUtils;
import android.view.HardwareCanvas;
import android.view.RenderNodeAnimator;
@@ -58,8 +59,10 @@
/** Bounds used for computing max radius. */
private final Rect mBounds;
- /** Full-opacity color for drawing this ripple. */
- private int mColorOpaque;
+ /** ARGB color for drawing this ripple. */
+ private int mColor;
+
+ private Xfermode mXfermode;
/** Maximum ripple radius. */
private float mOuterRadius;
@@ -120,9 +123,7 @@
mStartingY = startingY;
}
- public void setup(int maxRadius, int color, float density) {
- mColorOpaque = color | 0xFF000000;
-
+ public void setup(int maxRadius, float density) {
if (maxRadius != RippleDrawable.RADIUS_AUTO) {
mHasMaxRadius = true;
mOuterRadius = maxRadius;
@@ -216,6 +217,10 @@
* Draws the ripple centered at (0,0) using the specified paint.
*/
public boolean draw(Canvas c, Paint p) {
+ // Store the color and xfermode, we might need them later.
+ mColor = p.getColor();
+ mXfermode = p.getXfermode();
+
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
@@ -261,8 +266,8 @@
private boolean drawSoftware(Canvas c, Paint p) {
boolean hasContent = false;
- p.setColor(mColorOpaque);
- final int alpha = (int) (255 * mOpacity + 0.5f);
+ final int paintAlpha = p.getAlpha();
+ final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
if (alpha > 0 && radius > 0) {
final float x = MathUtils.lerp(
@@ -270,8 +275,8 @@
final float y = MathUtils.lerp(
mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
p.setAlpha(alpha);
- p.setStyle(Style.FILL);
c.drawCircle(x, y, radius, p);
+ p.setAlpha(paintAlpha);
hasContent = true;
}
@@ -374,8 +379,9 @@
final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final Paint paint = getTempPaint();
paint.setAntiAlias(true);
- paint.setColor(mColorOpaque);
- paint.setAlpha((int) (255 * mOpacity + 0.5f));
+ paint.setColor(mColor);
+ paint.setXfermode(mXfermode);
+ paint.setAlpha((int) (Color.alpha(mColor) * mOpacity + 0.5f));
paint.setStyle(Style.FILL);
mPropPaint = CanvasProperty.createPaint(paint);
mPropRadius = CanvasProperty.createFloat(startRadius);
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 21d865f..69847b5 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -26,6 +26,7 @@
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
+import android.graphics.Xfermode;
import android.util.MathUtils;
import android.view.HardwareCanvas;
import android.view.RenderNodeAnimator;
@@ -60,11 +61,10 @@
/** Bounds used for computing max radius. */
private final Rect mBounds;
- /** Full-opacity color for drawing this ripple. */
- private int mColorOpaque;
+ /** ARGB color for drawing this ripple. */
+ private int mColor;
- /** Maximum alpha value for drawing this ripple. */
- private int mColorAlpha;
+ private Xfermode mXfermode;
/** Maximum ripple radius. */
private float mOuterRadius;
@@ -106,10 +106,7 @@
mBounds = bounds;
}
- public void setup(int maxRadius, int color, float density) {
- mColorOpaque = color | 0xFF000000;
- mColorAlpha = Color.alpha(color) / 2;
-
+ public void setup(int maxRadius, float density) {
if (maxRadius != RippleDrawable.RADIUS_AUTO) {
mHasMaxRadius = true;
mOuterRadius = maxRadius;
@@ -124,10 +121,6 @@
mDensity = density;
}
- public boolean isHardwareAnimating() {
- return mHardwareAnimating;
- }
-
public void onHotspotBoundsChanged() {
if (!mHasMaxRadius) {
final float halfWidth = mBounds.width() / 2.0f;
@@ -151,6 +144,10 @@
* Draws the ripple centered at (0,0) using the specified paint.
*/
public boolean draw(Canvas c, Paint p) {
+ // Store the color and xfermode, we might need them later.
+ mColor = p.getColor();
+ mXfermode = p.getXfermode();
+
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
@@ -169,8 +166,7 @@
}
public boolean shouldDraw() {
- final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f);
- return mCanUseHardware && mHardwareAnimating || outerAlpha > 0 && mOuterRadius > 0;
+ return (mCanUseHardware && mHardwareAnimating) || (mOuterOpacity > 0 && mOuterRadius > 0);
}
private boolean drawHardware(HardwareCanvas c) {
@@ -201,12 +197,13 @@
private boolean drawSoftware(Canvas c, Paint p) {
boolean hasContent = false;
- p.setColor(mColorOpaque);
- final int outerAlpha = (int) (mColorAlpha * mOuterOpacity + 0.5f);
- if (outerAlpha > 0 && mOuterRadius > 0) {
- p.setAlpha(outerAlpha);
- p.setStyle(Style.FILL);
- c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+ final int paintAlpha = p.getAlpha();
+ final int alpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
+ final float radius = mOuterRadius;
+ if (alpha > 0 && radius > 0) {
+ p.setAlpha(alpha);
+ c.drawCircle(mOuterX, mOuterY, radius, p);
+ p.setAlpha(paintAlpha);
hasContent = true;
}
@@ -262,7 +259,7 @@
// outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
final int inflectionDuration = Math.max(0, (int) (1000 * (1 - mOuterOpacity)
/ (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
- final int inflectionOpacity = (int) (mColorAlpha * (mOuterOpacity
+ final int inflectionOpacity = (int) (Color.alpha(mColor) * (mOuterOpacity
+ inflectionDuration * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
if (mCanUseHardware) {
@@ -277,8 +274,9 @@
final Paint outerPaint = getTempPaint();
outerPaint.setAntiAlias(true);
- outerPaint.setColor(mColorOpaque);
- outerPaint.setAlpha((int) (mColorAlpha * mOuterOpacity + 0.5f));
+ outerPaint.setXfermode(mXfermode);
+ outerPaint.setColor(mColor);
+ outerPaint.setAlpha((int) (Color.alpha(mColor) * mOuterOpacity + 0.5f));
outerPaint.setStyle(Style.FILL);
mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index e658279..8cbc239 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -16,6 +16,11 @@
package android.graphics.drawable;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -34,11 +39,6 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.util.Arrays;
@@ -157,13 +157,6 @@
private boolean mOverrideBounds;
/**
- * Whether the next draw MUST draw something to canvas. Used to work around
- * a bug in hardware invalidation following a render thread-accelerated
- * animation.
- */
- private boolean mNeedsDraw;
-
- /**
* Constructor used for drawable inflation.
*/
RippleDrawable() {
@@ -203,21 +196,15 @@
public void jumpToCurrentState() {
super.jumpToCurrentState();
- boolean needsDraw = false;
-
if (mRipple != null) {
- needsDraw |= mRipple.isHardwareAnimating();
mRipple.jump();
}
if (mBackground != null) {
- needsDraw |= mBackground.isHardwareAnimating();
mBackground.jump();
}
- needsDraw |= cancelExitingRipples();
-
- mNeedsDraw = needsDraw;
+ cancelExitingRipples();
invalidateSelf();
}
@@ -497,8 +484,7 @@
mBackground = new RippleBackground(this, mHotspotBounds);
}
- final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
- mBackground.setup(mState.mMaxRadius, color, mDensity);
+ mBackground.setup(mState.mMaxRadius, mDensity);
mBackground.enter(focused);
}
@@ -534,8 +520,7 @@
mRipple = new Ripple(this, mHotspotBounds, x, y);
}
- final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
- mRipple.setup(mState.mMaxRadius, color, mDensity);
+ mRipple.setup(mState.mMaxRadius, mDensity);
mRipple.enter();
}
@@ -559,23 +544,17 @@
* background. Nothing will be drawn after this method is called.
*/
private void clearHotspots() {
- boolean needsDraw = false;
-
if (mRipple != null) {
- needsDraw |= mRipple.isHardwareAnimating();
mRipple.cancel();
mRipple = null;
}
if (mBackground != null) {
- needsDraw |= mBackground.isHardwareAnimating();
mBackground.cancel();
mBackground = null;
}
- needsDraw |= cancelExitingRipples();
-
- mNeedsDraw = needsDraw;
+ cancelExitingRipples();
invalidateSelf();
}
@@ -631,56 +610,41 @@
}
}
+ /**
+ * Optimized for drawing ripples with a mask layer and optional content.
+ */
@Override
public void draw(@NonNull Canvas canvas) {
final boolean hasMask = mMask != null;
- final boolean drawNonMaskContent = mLayerState.mNum > (hasMask ? 1 : 0);
- final boolean drawMask = hasMask && mMask.getOpacity() != PixelFormat.OPAQUE;
+ final boolean hasRipples = mRipple != null || mExitingRipplesCount > 0
+ || (mBackground != null && mBackground.shouldDraw());
+
+ // Clip to the dirty bounds, which will be the drawable bounds if we
+ // have a mask or content and the ripple bounds if we're projecting.
final Rect bounds = getDirtyBounds();
final int saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(bounds);
- // If we have content, draw it into a layer first.
- final int contentLayer;
- if (drawNonMaskContent) {
- contentLayer = drawContentLayer(canvas, bounds, SRC_OVER);
- } else {
- contentLayer = -1;
- }
+ // If we have content, draw it first. If we have ripples and no mask,
+ // we'll draw it into a SRC_OVER layer so that we can mask ripples
+ // against it using SRC_IN.
+ final boolean hasContentLayer = drawContent(canvas, bounds, hasRipples, hasMask);
- // Next, try to draw the ripples (into a layer if necessary). If we need
- // to mask against the underlying content, set the xfermode to SRC_ATOP.
- final PorterDuffXfermode xfermode = (hasMask || !drawNonMaskContent) ? SRC_OVER : SRC_ATOP;
+ // Next, try to draw the ripples. If we have a non-opaque mask, we'll
+ // draw the ripples into a SRC_OVER layer, draw the mask into a DST_IN
+ // layer, and blend.
+ if (hasRipples) {
+ final boolean hasNonOpaqueMask = hasMask && mMask.getOpacity() != PixelFormat.OPAQUE;
+ final boolean hasRippleLayer = drawBackgroundAndRipples(canvas, bounds,
+ hasNonOpaqueMask, hasContentLayer);
- // If we have a background and a non-opaque mask, draw the masking layer.
- final int backgroundLayer = drawBackgroundLayer(canvas, bounds, xfermode, drawMask);
- if (backgroundLayer >= 0) {
- if (drawMask) {
+ // If drawing ripples created a layer, we have a non-opaque mask
+ // that needs to be blended on top of the ripples with DST_IN.
+ if (hasRippleLayer) {
drawMaskingLayer(canvas, bounds, DST_IN);
}
- canvas.restoreToCount(backgroundLayer);
}
- // If we have ripples and a non-opaque mask, draw the masking layer.
- final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode);
- if (rippleLayer >= 0) {
- if (drawMask) {
- drawMaskingLayer(canvas, bounds, DST_IN);
- }
- canvas.restoreToCount(rippleLayer);
- }
-
- // If we failed to draw anything and we just canceled animations, at
- // least draw a color so that hardware invalidation works correctly.
- if (contentLayer < 0 && backgroundLayer < 0 && rippleLayer < 0 && mNeedsDraw) {
- canvas.drawColor(Color.TRANSPARENT);
-
- // Request another draw so we can avoid adding a transparent layer
- // during the next display list refresh.
- invalidateSelf();
- }
- mNeedsDraw = false;
-
canvas.restoreToCount(saveCount);
}
@@ -714,28 +678,27 @@
return -1;
}
- private int drawContentLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
+ private boolean drawContent(Canvas canvas, Rect bounds, boolean hasRipples, boolean hasMask) {
final ChildDrawable[] array = mLayerState.mChildren;
final int count = mLayerState.mNum;
- // We don't need a layer if we don't expect to draw any ripples or
- // a background, we have an explicit mask, or if the non-mask content
- // is all opaque.
boolean needsLayer = false;
- if ((mExitingRipplesCount > 0 || (mBackground != null && mBackground.shouldDraw()))
- && mMask == null) {
+
+ if (hasRipples && !hasMask) {
+ // If we only have opaque content, we don't really need a layer
+ // because the ripples will be clipped to the drawable bounds.
for (int i = 0; i < count; i++) {
- if (array[i].mId != R.id.mask
- && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
+ if (array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
needsLayer = true;
break;
}
}
}
- final Paint maskingPaint = getMaskingPaint(mode);
- final int restoreToCount = needsLayer ? canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, maskingPaint) : -1;
+ if (needsLayer) {
+ canvas.saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
+ getMaskingPaint(SRC_OVER));
+ }
// Draw everything except the mask.
for (int i = 0; i < count; i++) {
@@ -744,82 +707,52 @@
}
}
- return restoreToCount;
+ return needsLayer;
}
- private int drawBackgroundLayer(
- Canvas canvas, Rect bounds, PorterDuffXfermode mode, boolean drawMask) {
- int saveCount = -1;
-
- if (mBackground != null && mBackground.shouldDraw()) {
- // TODO: We can avoid saveLayer here if we push the xfermode into
- // the background's render thread animator at exit() time.
- if (drawMask || mode != SRC_OVER) {
- saveCount = canvas.saveLayer(bounds.left, bounds.top, bounds.right,
- bounds.bottom, getMaskingPaint(mode));
- }
-
- final float x = mHotspotBounds.exactCenterX();
- final float y = mHotspotBounds.exactCenterY();
- canvas.translate(x, y);
- mBackground.draw(canvas, getRipplePaint());
- canvas.translate(-x, -y);
+ private boolean drawBackgroundAndRipples(
+ Canvas canvas, Rect bounds, boolean hasNonOpaqueMask, boolean hasContentLayer) {
+ if (hasNonOpaqueMask) {
+ final Paint p = getMaskingPaint(SRC_OVER);
+ canvas.saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, p);
}
- return saveCount;
- }
+ final PorterDuffXfermode mode = hasContentLayer ? SRC_ATOP : SRC_OVER;
+ final float x = mHotspotBounds.exactCenterX();
+ final float y = mHotspotBounds.exactCenterY();
+ canvas.translate(x, y);
- private int drawRippleLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
- boolean drewRipples = false;
- int restoreToCount = -1;
- int restoreTranslate = -1;
+ final Paint p = getRipplePaint();
+ p.setXfermode(mode);
- // Draw ripples and update the animating ripples array.
+ // Grab the color for the current state and cut the alpha channel in
+ // half so that the ripple and background together yield full alpha.
+ final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
+ final int alpha = (Color.alpha(color) / 2) << 24;
+ p.setColor(color & 0xFFFFFF | alpha);
+
+ final RippleBackground background = mBackground;
+ if (background != null && background.shouldDraw()) {
+ background.draw(canvas, p);
+ }
+
final int count = mExitingRipplesCount;
- final Ripple[] ripples = mExitingRipples;
- for (int i = 0; i <= count; i++) {
- final Ripple ripple;
- if (i < count) {
- ripple = ripples[i];
- } else if (mRipple != null) {
- ripple = mRipple;
- } else {
- continue;
+ if (count > 0) {
+ final Ripple[] ripples = mExitingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].draw(canvas, p);
}
-
- // If we're masking the ripple layer, make sure we have a layer
- // first. This will merge SRC_OVER (directly) onto the canvas.
- if (restoreToCount < 0) {
- final Paint maskingPaint = getMaskingPaint(mode);
- final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
- final int alpha = Color.alpha(color);
- maskingPaint.setAlpha(alpha / 2);
-
- // TODO: We can avoid saveLayer here if we're only drawing one
- // ripple and we don't have content or a translucent mask.
- restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, maskingPaint);
-
- // Translate the canvas to the current hotspot bounds.
- restoreTranslate = canvas.save();
- canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
- }
-
- drewRipples |= ripple.draw(canvas, getRipplePaint());
}
- // Always restore the translation.
- if (restoreTranslate >= 0) {
- canvas.restoreToCount(restoreTranslate);
+ final Ripple active = mRipple;
+ if (active != null) {
+ active.draw(canvas, p);
}
- // If we created a layer with no content, merge it immediately.
- if (restoreToCount >= 0 && !drewRipples) {
- canvas.restoreToCount(restoreToCount);
- restoreToCount = -1;
- }
+ canvas.translate(-x, -y);
- return restoreToCount;
+ // Returns true if a layer was created.
+ return hasNonOpaqueMask;
}
private int drawMaskingLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
@@ -838,6 +771,7 @@
if (mRipplePaint == null) {
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
+ mRipplePaint.setStyle(Paint.Style.FILL);
}
return mRipplePaint;
}
diff --git a/packages/Keyguard/res/layout-land/keyguard_host_view.xml b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
index 1d596d3..891910e 100644
--- a/packages/Keyguard/res/layout-land/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-land/keyguard_host_view.xml
@@ -25,14 +25,17 @@
android:id="@+id/keyguard_host_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<com.android.keyguard.MultiPaneChallengeLayout
android:id="@+id/multi_pane_challenge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:clipToPadding="false">
<include layout="@layout/keyguard_widget_remove_drop_target"
android:id="@+id/keyguard_widget_pager_delete_target"
diff --git a/packages/Keyguard/res/layout-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
index 8223db4..1b8820b 100644
--- a/packages/Keyguard/res/layout-port/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-port/keyguard_host_view.xml
@@ -26,13 +26,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical">
<com.android.keyguard.SlidingChallengeLayout
android:id="@+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:clipToPadding="false">
<FrameLayout
android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
index ba2f3a6..f2f3981 100644
--- a/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/packages/Keyguard/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -25,13 +25,16 @@
android:id="@+id/keyguard_host_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<com.android.keyguard.MultiPaneChallengeLayout
android:id="@+id/multi_pane_challenge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical">
<include layout="@layout/keyguard_widget_remove_drop_target"
diff --git a/packages/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
index 3c1f65e..296efb3 100644
--- a/packages/Keyguard/res/layout/keyguard_bouncer.xml
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -18,12 +18,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:fitsSystemWindows="true">
<include
style="@style/BouncerSecurityContainer"
layout="@layout/keyguard_simple_host_view"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content" />
</FrameLayout>
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index bd585b5..1fb0420 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -27,6 +27,8 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
android:gravity="center_horizontal"
@@ -34,13 +36,17 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical"
- android:layout_gravity="center_horizontal|bottom">
+ android:layout_gravity="center_horizontal|bottom"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<include layout="@layout/keyguard_message_area"
android:layout_width="match_parent"
@@ -52,6 +58,8 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
>
<com.android.internal.widget.LockPatternView
android:id="@+id/lockPatternView"
@@ -63,7 +71,9 @@
android:layout_marginStart="8dip"
android:layout_gravity="center_horizontal"
android:gravity="center"
- android:contentDescription="@string/keyguard_accessibility_pattern_area" />
+ android:contentDescription="@string/keyguard_accessibility_pattern_area"
+ android:clipChildren="false"
+ android:clipToPadding="false" />
</FrameLayout>
<include layout="@layout/keyguard_eca"
android:id="@+id/keyguard_selector_fade_container"
diff --git a/packages/Keyguard/res/layout/keyguard_simple_host_view.xml b/packages/Keyguard/res/layout/keyguard_simple_host_view.xml
index 4336e1c..28ce265 100644
--- a/packages/Keyguard/res/layout/keyguard_simple_host_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_simple_host_view.xml
@@ -24,7 +24,9 @@
xmlns:androidprv="http://schemas.android.com/apk/res-auto"
android:id="@+id/keyguard_host_view"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<com.android.keyguard.KeyguardSecurityContainer
android:id="@+id/keyguard_security_container"
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
index 0d30ea6..3ff2cc0 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
@@ -25,5 +25,6 @@
*/
public interface AppearAnimationCreator<T> {
void createAnimation(T animatedObject, long delay, long duration,
- float startTranslationY, Interpolator interpolator, Runnable finishListener);
+ float translationY, boolean appearing, Interpolator interpolator,
+ Runnable finishListener);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
index b685c73..9045fe3 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
@@ -31,8 +31,10 @@
private final Interpolator mInterpolator;
private final float mStartTranslation;
private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
- private final float mDelayScale;
+ protected final float mDelayScale;
private final long mDuration;
+ protected boolean mScaleTranslationWithRow;
+ protected boolean mAppearing;
public AppearAnimationUtils(Context ctx) {
this(ctx, DEFAULT_APPEAR_DURATION,
@@ -47,23 +49,25 @@
R.dimen.appear_y_translation_start) * translationScaleFactor;
mDelayScale = delayScaleFactor;
mDuration = duration;
+ mScaleTranslationWithRow = false;
+ mAppearing = true;
}
- public void startAppearAnimation(View[][] objects, final Runnable finishListener) {
- startAppearAnimation(objects, finishListener, this);
+ public void startAnimation(View[][] objects, final Runnable finishListener) {
+ startAnimation(objects, finishListener, this);
}
- public void startAppearAnimation(View[] objects, final Runnable finishListener) {
- startAppearAnimation(objects, finishListener, this);
+ public void startAnimation(View[] objects, final Runnable finishListener) {
+ startAnimation(objects, finishListener, this);
}
- public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener,
+ public <T> void startAnimation(T[][] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
}
- public <T> void startAppearAnimation(T[] objects, final Runnable finishListener,
+ public <T> void startAnimation(T[] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
@@ -83,7 +87,7 @@
endRunnable = finishListener;
}
creator.createAnimation(objects[row], delay, mDuration,
- mStartTranslation, mInterpolator, endRunnable);
+ mStartTranslation, true /* appearing */, mInterpolator, endRunnable);
}
}
@@ -95,6 +99,10 @@
}
for (int row = 0; row < properties.delays.length; row++) {
long[] columns = properties.delays[row];
+ float translation = mScaleTranslationWithRow
+ ? (float) (Math.pow((properties.delays.length - row), 2)
+ / properties.delays.length * mStartTranslation)
+ : mStartTranslation;
for (int col = 0; col < columns.length; col++) {
long delay = columns[col];
Runnable endRunnable = null;
@@ -102,7 +110,8 @@
endRunnable = finishListener;
}
creator.createAnimation(objects[row][col], delay, mDuration,
- mStartTranslation, mInterpolator, endRunnable);
+ mAppearing ? translation : -translation,
+ mAppearing, mInterpolator, endRunnable);
}
}
}
@@ -146,7 +155,7 @@
return mProperties;
}
- private long calculateDelay(int row, int col) {
+ protected long calculateDelay(int row, int col) {
return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale);
}
@@ -159,14 +168,14 @@
}
@Override
- public void createAnimation(View view, long delay, long duration, float startTranslationY,
- Interpolator interpolator, Runnable endRunnable) {
+ public void createAnimation(View view, long delay, long duration, float translationY,
+ boolean appearing, Interpolator interpolator, Runnable endRunnable) {
if (view != null) {
- view.setAlpha(0f);
- view.setTranslationY(startTranslationY);
+ view.setAlpha(appearing ? 0f : 1.0f);
+ view.setTranslationY(appearing ? translationY : 0);
view.animate()
- .alpha(1f)
- .translationY(0)
+ .alpha(appearing ? 1f : 0f)
+ .translationY(appearing ? 0 : translationY)
.setInterpolator(interpolator)
.setDuration(duration)
.setStartDelay(delay);
diff --git a/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
new file mode 100644
index 0000000..6fff0ba
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 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.keyguard;
+
+import android.content.Context;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+/**
+ * A class to make nice disappear transitions for views in a tabular layout.
+ */
+public class DisappearAnimationUtils extends AppearAnimationUtils {
+
+ public DisappearAnimationUtils(Context ctx) {
+ this(ctx, DEFAULT_APPEAR_DURATION,
+ 1.0f, 1.0f,
+ AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
+ }
+
+ public DisappearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
+ float delayScaleFactor, Interpolator interpolator) {
+ super(ctx, duration, translationScaleFactor, delayScaleFactor, interpolator);
+ mScaleTranslationWithRow = true;
+ mAppearing = false;
+ }
+
+ protected long calculateDelay(int row, int col) {
+ return (long) ((row * 60 + col * (Math.pow(row, 0.4) + 0.4) * 10) * mDelayScale);
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index 55538a7..04ef57e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -28,6 +28,7 @@
public class KeyguardPINView extends KeyguardPinBasedInputView {
private final AppearAnimationUtils mAppearAnimationUtils;
+ private final DisappearAnimationUtils mDisappearAnimationUtils;
private ViewGroup mKeyguardBouncerFrame;
private ViewGroup mRow0;
private ViewGroup mRow1;
@@ -35,6 +36,7 @@
private ViewGroup mRow3;
private View mDivider;
private int mDisappearYTranslation;
+ private View[][] mViews;
public KeyguardPINView(Context context) {
this(context, null);
@@ -43,6 +45,10 @@
public KeyguardPINView(Context context, AttributeSet attrs) {
super(context, attrs);
mAppearAnimationUtils = new AppearAnimationUtils(context);
+ mDisappearAnimationUtils = new DisappearAnimationUtils(context,
+ 125, 0.6f /* translationScale */,
+ 0.6f /* delayScale */, AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
}
@@ -71,6 +77,28 @@
mRow2 = (ViewGroup) findViewById(R.id.row2);
mRow3 = (ViewGroup) findViewById(R.id.row3);
mDivider = findViewById(R.id.divider);
+ mViews = new View[][]{
+ new View[]{
+ mRow0, null, null
+ },
+ new View[]{
+ findViewById(R.id.key1), findViewById(R.id.key2),
+ findViewById(R.id.key3)
+ },
+ new View[]{
+ findViewById(R.id.key4), findViewById(R.id.key5),
+ findViewById(R.id.key6)
+ },
+ new View[]{
+ findViewById(R.id.key7), findViewById(R.id.key8),
+ findViewById(R.id.key9)
+ },
+ new View[]{
+ null, findViewById(R.id.key0), findViewById(R.id.key_enter)
+ },
+ new View[]{
+ null, mEcaView, null
+ }};
}
@Override
@@ -91,25 +119,7 @@
.setDuration(500)
.setInterpolator(mAppearAnimationUtils.getInterpolator())
.translationY(0);
- mAppearAnimationUtils.startAppearAnimation(new View[][] {
- new View[] {
- mRow0, null, null
- },
- new View[] {
- findViewById(R.id.key1), findViewById(R.id.key2), findViewById(R.id.key3)
- },
- new View[] {
- findViewById(R.id.key4), findViewById(R.id.key5), findViewById(R.id.key6)
- },
- new View[] {
- findViewById(R.id.key7), findViewById(R.id.key8), findViewById(R.id.key9)
- },
- new View[] {
- null, findViewById(R.id.key0), findViewById(R.id.key_enter)
- },
- new View[] {
- null, mEcaView, null
- }},
+ mAppearAnimationUtils.startAnimation(mViews,
new Runnable() {
@Override
public void run() {
@@ -119,14 +129,23 @@
}
@Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
+ public boolean startDisappearAnimation(final Runnable finishRunnable) {
+ enableClipping(false);
+ setTranslationY(0);
animate()
- .alpha(0f)
- .translationY(mDisappearYTranslation)
- .setInterpolator(AnimationUtils
- .loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in))
- .setDuration(100)
- .withEndAction(finishRunnable);
+ .setDuration(280)
+ .setInterpolator(mDisappearAnimationUtils.getInterpolator())
+ .translationY(mDisappearYTranslation);
+ mDisappearAnimationUtils.startAnimation(mViews,
+ new Runnable() {
+ @Override
+ public void run() {
+ enableClipping(true);
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
return true;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 0e01a27..3212eec 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -55,6 +55,7 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final AppearAnimationUtils mAppearAnimationUtils;
+ private final DisappearAnimationUtils mDisappearAnimationUtils;
private CountDownTimer mCountdownTimer = null;
private LockPatternUtils mLockPatternUtils;
@@ -99,9 +100,13 @@
super(context, attrs);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
mAppearAnimationUtils = new AppearAnimationUtils(context,
- AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* delayScale */,
- 2.0f /* transitionScale */, AnimationUtils.loadInterpolator(
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* translationScale */,
+ 2.0f /* delayScale */, AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.linear_out_slow_in));
+ mDisappearAnimationUtils = new DisappearAnimationUtils(context,
+ 125, 1.2f /* translationScale */,
+ 0.8f /* delayScale */, AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
}
@@ -303,7 +308,7 @@
.setDuration(500)
.setInterpolator(mAppearAnimationUtils.getInterpolator())
.translationY(0);
- mAppearAnimationUtils.startAppearAnimation(
+ mAppearAnimationUtils.startAnimation(
mLockPatternView.getCellStates(),
new Runnable() {
@Override
@@ -316,21 +321,39 @@
mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
mAppearAnimationUtils.getStartTranslation(),
+ true /* appearing */,
mAppearAnimationUtils.getInterpolator(),
null /* finishRunnable */);
}
}
@Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
+ public boolean startDisappearAnimation(final Runnable finishRunnable) {
mLockPatternView.clearPattern();
+ enableClipping(false);
+ setTranslationY(0);
animate()
- .alpha(0f)
- .translationY(mDisappearYTranslation)
- .setInterpolator(AnimationUtils.loadInterpolator(
- mContext, android.R.interpolator.fast_out_linear_in))
- .setDuration(100)
- .withEndAction(finishRunnable);
+ .setDuration(300)
+ .setInterpolator(mDisappearAnimationUtils.getInterpolator())
+ .translationY(-mDisappearAnimationUtils.getStartTranslation());
+ mDisappearAnimationUtils.startAnimation(mLockPatternView.getCellStates(),
+ new Runnable() {
+ @Override
+ public void run() {
+ enableClipping(true);
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ }, KeyguardPatternView.this);
+ if (!TextUtils.isEmpty(mHelpMessage.getText())) {
+ mDisappearAnimationUtils.createAnimation(mHelpMessage, 0,
+ 200,
+ - mDisappearAnimationUtils.getStartTranslation() * 3,
+ false /* appearing */,
+ mDisappearAnimationUtils.getInterpolator(),
+ null /* finishRunnable */);
+ }
return true;
}
@@ -342,11 +365,15 @@
@Override
public void createAnimation(final LockPatternView.CellState animatedCell, long delay,
- long duration, float startTranslationY, Interpolator interpolator,
+ long duration, float translationY, final boolean appearing,
+ Interpolator interpolator,
final Runnable finishListener) {
- animatedCell.scale = 0.0f;
- animatedCell.translateY = startTranslationY;
- ValueAnimator animator = ValueAnimator.ofFloat(startTranslationY, 0.0f);
+ if (appearing) {
+ animatedCell.scale = 0.0f;
+ }
+ animatedCell.translateY = appearing ? translationY : 0;
+ ValueAnimator animator = ValueAnimator.ofFloat(animatedCell.translateY,
+ appearing ? 0 : translationY);
animator.setInterpolator(interpolator);
animator.setDuration(duration);
animator.setStartDelay(delay);
@@ -354,7 +381,11 @@
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedFraction = animation.getAnimatedFraction();
- animatedCell.scale = animatedFraction;
+ if (appearing) {
+ animatedCell.scale = animatedFraction;
+ } else {
+ animatedCell.alpha = 1 - animatedFraction;
+ }
animatedCell.translateY = (float) animation.getAnimatedValue();
mLockPatternView.invalidate();
}
@@ -368,8 +399,8 @@
});
// Also animate the Emergency call
- mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, startTranslationY,
- interpolator, null);
+ mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, translationY,
+ appearing, interpolator, null);
}
animator.start();
mLockPatternView.invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 172aaf6..20e418c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -113,6 +113,8 @@
*/
public class KeyguardViewMediator extends SystemUI {
private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000;
+ private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
+
final static boolean DEBUG = false;
private final static boolean DBG_WAKE = false;
@@ -136,6 +138,7 @@
private static final int DISMISS = 17;
private static final int START_KEYGUARD_EXIT_ANIM = 18;
private static final int ON_ACTIVITY_DRAWN = 19;
+ private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 20;
/**
* The default amount of time we stay awake (used for all key input)
@@ -294,7 +297,7 @@
// ActivityManagerService) will not reconstruct the keyguard if it is already showing.
synchronized (KeyguardViewMediator.this) {
mSwitchingUser = true;
- mKeyguardDonePending = false;
+ resetKeyguardDonePendingLocked();
resetStateLocked();
adjustStatusBarLocked();
// When we switch users we want to bring the new user to the biometric unlock even
@@ -426,7 +429,9 @@
}
public void keyguardDone(boolean authenticated) {
- KeyguardViewMediator.this.keyguardDone(authenticated, true);
+ if (!mKeyguardDonePending) {
+ KeyguardViewMediator.this.keyguardDone(authenticated, true);
+ }
}
public void keyguardDoneDrawing() {
@@ -448,6 +453,8 @@
mKeyguardDonePending = true;
mHideAnimationRun = true;
mStatusBarKeyguardViewManager.startPreHideAnimation(null /* finishRunnable */);
+ mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
+ KEYGUARD_DONE_PENDING_TIMEOUT_MS);
}
@Override
@@ -582,7 +589,7 @@
mScreenOn = false;
if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")");
- mKeyguardDonePending = false;
+ resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
// Lock immediately based on setting if secure (user has a pin/pattern/password).
@@ -1049,9 +1056,6 @@
public void keyguardDone(boolean authenticated, boolean wakeup) {
if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
EventLog.writeEvent(70000, 2);
- synchronized (this) {
- mKeyguardDonePending = false;
- }
Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0, wakeup ? 1 : 0);
mHandler.sendMessage(msg);
}
@@ -1109,6 +1113,9 @@
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
break;
+ case KEYGUARD_DONE_PENDING_TIMEOUT:
+ Log.w(TAG, "Timeout while waiting for activity drawn!");
+ // Fall through.
case ON_ACTIVITY_DRAWN:
handleOnActivityDrawn();
break;
@@ -1122,6 +1129,9 @@
*/
private void handleKeyguardDone(boolean authenticated, boolean wakeup) {
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
+ synchronized (this) {
+ resetKeyguardDonePendingLocked();
+ }
if (authenticated) {
mUpdateMonitor.clearFailedUnlockAttempts();
@@ -1240,7 +1250,7 @@
mStatusBarKeyguardViewManager.show(options);
mHiding = false;
mShowing = true;
- mKeyguardDonePending = false;
+ resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
updateActivityLockScreenState();
adjustStatusBarLocked();
@@ -1297,6 +1307,7 @@
}
private void handleOnActivityDrawn() {
+ if (DEBUG) Log.d(TAG, "handleOnActivityDrawn: mKeyguardDonePending=" + mKeyguardDonePending);
if (mKeyguardDonePending) {
mStatusBarKeyguardViewManager.onActivityDrawn();
}
@@ -1318,7 +1329,7 @@
mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
mShowing = false;
- mKeyguardDonePending = false;
+ resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
updateActivityLockScreenState();
adjustStatusBarLocked();
@@ -1414,6 +1425,11 @@
&& mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
}
+ private void resetKeyguardDonePendingLocked() {
+ mKeyguardDonePending = false;
+ mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT);
+ }
+
public void onBootCompleted() {
mUpdateMonitor.dispatchBootCompleted();
synchronized (this) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 725a1a8..5613a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1486,8 +1486,6 @@
entry.autoRedacted = true;
}
- row.setClearable(sbn.isClearable());
-
if (MULTIUSER_DEBUG) {
TextView debug = (TextView) row.findViewById(R.id.debug_info);
if (debug != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index f8332ea..7345440 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -118,6 +118,7 @@
public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
mStatusBarNotification = statusBarNotification;
+ updateVetoButton();
}
public StatusBarNotification getStatusBarNotification() {
@@ -303,17 +304,7 @@
* @return Can the underlying notification be cleared?
*/
public boolean isClearable() {
- return mClearable;
- }
-
- /**
- * Set whether the notification can be cleared.
- *
- * @param clearable
- */
- public void setClearable(boolean clearable) {
- mClearable = clearable;
- updateVetoButton();
+ return mStatusBarNotification != null && mStatusBarNotification.isClearable();
}
/**
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 1697646..881b38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3123,18 +3123,7 @@
protected void dismissKeyguardThenExecute(final OnDismissAction action,
boolean afterKeyguardGone) {
if (mStatusBarKeyguardViewManager.isShowing()) {
- if (UnlockMethodCache.getInstance(mContext).isMethodInsecure()
- && mNotificationPanel.isLaunchTransitionRunning() && !afterKeyguardGone) {
- action.onDismiss();
- mNotificationPanel.setLaunchTransitionEndRunnable(new Runnable() {
- @Override
- public void run() {
- mStatusBarKeyguardViewManager.dismiss();
- }
- });
- } else {
- mStatusBarKeyguardViewManager.dismissWithAction(action, afterKeyguardGone);
- }
+ mStatusBarKeyguardViewManager.dismissWithAction(action, afterKeyguardGone);
} else {
action.onDismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 297ff70..c71bccd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -145,7 +145,7 @@
}
mUserSwitcher.setClipChildren(false);
mUserSwitcher.setClipToPadding(false);
- mAppearAnimationUtils.startAppearAnimation(objects, new Runnable() {
+ mAppearAnimationUtils.startAnimation(objects, new Runnable() {
@Override
public void run() {
mUserSwitcher.setClipChildren(true);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index ae84846..77662cc 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -43,13 +43,10 @@
import android.provider.Settings.SettingNotFoundException;
import android.security.KeyStore;
import android.text.TextUtils;
-import android.util.Log;
import android.util.Slog;
import com.android.internal.widget.ILockSettings;
-import com.android.internal.widget.ILockSettingsObserver;
import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtilsCache;
import java.util.ArrayList;
import java.util.Arrays;
@@ -65,9 +62,6 @@
private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
- private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
-
-
private static final String TAG = "LockSettingsService";
private final Context mContext;
@@ -77,8 +71,6 @@
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
- private final ArrayList<LockSettingsObserver> mObservers = new ArrayList<>();
-
public LockSettingsService(Context context) {
mContext = context;
// Open the database
@@ -233,7 +225,6 @@
private void setStringUnchecked(String key, int userId, String value) {
mStorage.writeKeyValue(key, value, userId);
- notifyObservers(key, userId);
}
@Override
@@ -261,52 +252,6 @@
}
@Override
- public void registerObserver(ILockSettingsObserver remote) throws RemoteException {
- synchronized (mObservers) {
- for (int i = 0; i < mObservers.size(); i++) {
- if (mObservers.get(i).remote.asBinder() == remote.asBinder()) {
- boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
- if (isDebuggable) {
- throw new IllegalStateException("Observer was already registered.");
- } else {
- Log.e(TAG, "Observer was already registered.");
- return;
- }
- }
- }
- LockSettingsObserver o = new LockSettingsObserver();
- o.remote = remote;
- o.remote.asBinder().linkToDeath(o, 0);
- mObservers.add(o);
- }
- }
-
- @Override
- public void unregisterObserver(ILockSettingsObserver remote) throws RemoteException {
- synchronized (mObservers) {
- for (int i = 0; i < mObservers.size(); i++) {
- if (mObservers.get(i).remote.asBinder() == remote.asBinder()) {
- mObservers.remove(i);
- return;
- }
- }
- }
- }
-
- public void notifyObservers(String key, int userId) {
- synchronized (mObservers) {
- for (int i = 0; i < mObservers.size(); i++) {
- try {
- mObservers.get(i).remote.onLockSettingChanged(key, userId);
- } catch (RemoteException e) {
- // The stack trace is not really helpful here.
- Log.e(TAG, "Failed to notify ILockSettingsObserver: " + e);
- }
- }
- }
- }
-
- @Override
public boolean havePassword(int userId) throws RemoteException {
// Do we need a permissions check here?
@@ -354,7 +299,6 @@
final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
mStorage.writePatternHash(hash, userId);
- notifyObservers(LockPatternUtilsCache.HAS_LOCK_PATTERN_CACHE_KEY, userId);
}
@Override
@@ -364,7 +308,6 @@
maybeUpdateKeystore(password, userId);
mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
- notifyObservers(LockPatternUtilsCache.HAS_LOCK_PASSWORD_CACHE_KEY, userId);
}
@Override
@@ -452,7 +395,6 @@
checkWritePermission(userId);
mStorage.removeUser(userId);
- notifyObservers(null /* key */, userId);
final KeyStore ks = KeyStore.getInstance();
final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
@@ -491,13 +433,4 @@
}
return null;
}
-
- private class LockSettingsObserver implements DeathRecipient {
- ILockSettingsObserver remote;
-
- @Override
- public void binderDied() {
- mObservers.remove(this);
- }
- }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 682642e..d0f5eed 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -81,6 +81,7 @@
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerService;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.AppTransition;
@@ -372,6 +373,8 @@
/** All system services */
SystemServiceManager mSystemServiceManager;
+ private Installer mInstaller;
+
/** Run all ActivityStacks through this */
ActivityStackSupervisor mStackSupervisor;
@@ -2169,6 +2172,10 @@
mSystemServiceManager = mgr;
}
+ public void setInstaller(Installer installer) {
+ mInstaller = installer;
+ }
+
private void start() {
Process.removeAllProcessGroups();
mProcessCpuThread.start();
@@ -6147,6 +6154,18 @@
mCallFinishBooting = false;
}
+ ArraySet<String> completedIsas = new ArraySet<String>();
+ for (String abi : Build.SUPPORTED_ABIS) {
+ Process.establishZygoteConnectionForAbi(abi);
+ final String instructionSet = VMRuntime.getInstructionSet(abi);
+ if (!completedIsas.contains(instructionSet)) {
+ if (mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi)) != 0) {
+ Slog.e(TAG, "Unable to mark boot complete for abi: " + abi);
+ }
+ completedIsas.add(instructionSet);
+ }
+ }
+
// Register receivers to handle package update events
mPackageMonitor.register(mContext, Looper.getMainLooper(), UserHandle.ALL, false);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0dae028..3a1fafe 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1538,9 +1538,6 @@
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
-
- // Make sure to notify Keyguard as well if it is waiting for an activity to be drawn.
- mStackSupervisor.notifyActivityDrawnForKeyguard();
return false;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 099151f..120002e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -656,7 +656,6 @@
void reportActivityVisibleLocked(ActivityRecord r) {
sendWaitingVisibleReportLocked(r);
- notifyActivityDrawnForKeyguard();
}
void sendWaitingVisibleReportLocked(ActivityRecord r) {
@@ -1832,6 +1831,7 @@
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
+ boolean movedToFront = false;
if (curTop != null && (curTop.task != intentActivity.task ||
curTop.task != lastStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
@@ -1851,6 +1851,7 @@
intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
}
options = null;
+ movedToFront = true;
}
}
// If the caller has requested that the target task be
@@ -1865,6 +1866,12 @@
// sure we have correctly resumed the top activity.
if (doResume) {
resumeTopActivitiesLocked(targetStack, null, options);
+
+ // Make sure to notify Keyguard as well if we are not running an app
+ // transition later.
+ if (!movedToFront) {
+ notifyActivityDrawnForKeyguard();
+ }
} else {
ActivityOptions.abort(options);
}
@@ -1956,6 +1963,11 @@
// sure we have correctly resumed the top activity.
if (doResume) {
targetStack.resumeTopActivityLocked(null, options);
+ if (!movedToFront) {
+ // Make sure to notify Keyguard as well if we are not running an app
+ // transition later.
+ notifyActivityDrawnForKeyguard();
+ }
} else {
ActivityOptions.abort(options);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index ca11862..31c604f 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -216,6 +216,18 @@
return mInstaller.execute(builder.toString());
}
+ public int markBootComplete(String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
+ StringBuilder builder = new StringBuilder("markbootcomplete");
+ builder.append(' ');
+ builder.append(instructionSet);
+ return mInstaller.execute(builder.toString());
+ }
+
public boolean ping() {
if (mInstaller.execute("ping") < 0) {
return false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a559bdd..25c31c1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1423,8 +1423,6 @@
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
- boolean didDexOptLibraryOrTool = false;
-
final List<String> allInstructionSets = getAllInstructionSets();
final String[] dexCodeInstructionSets =
getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
@@ -1457,7 +1455,6 @@
} else {
mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
}
- didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -1508,10 +1505,8 @@
false);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
- didDexOptLibraryOrTool = true;
} else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
- didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index b2bcf75..4906bd1 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -39,9 +39,7 @@
import android.util.Slog;
import android.service.trust.ITrustAgentService;
import android.service.trust.ITrustAgentServiceCallback;
-import android.service.trust.TrustAgentService;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -160,7 +158,7 @@
mTrustManagerService.updateTrust(mUserId, false);
break;
case MSG_RESTART_TIMEOUT:
- unbind();
+ destroy();
mTrustManagerService.resetAgent(mName, mUserId);
break;
case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
@@ -367,7 +365,9 @@
return mMessage;
}
- public void unbind() {
+ public void destroy() {
+ mHandler.removeMessages(MSG_RESTART_TIMEOUT);
+
if (!mBound) {
return;
}
@@ -378,7 +378,6 @@
mTrustAgentService = null;
mSetTrustAgentFeaturesToken = null;
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
- mHandler.removeMessages(MSG_RESTART_TIMEOUT);
}
public boolean isConnected() {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index fe5cb33..2388c85 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -208,7 +208,8 @@
obsoleteAgents.addAll(mActiveAgents);
for (UserInfo userInfo : userInfos) {
- if (userInfo.partial || !userInfo.isEnabled() || userInfo.guestToRemove) continue;
+ if (userInfo == null || userInfo.partial || !userInfo.isEnabled()
+ || userInfo.guestToRemove) continue;
if (!userInfo.supportsSwitchTo()) continue;
if (!mActivityManager.isUserRunning(userInfo.id)) continue;
if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
@@ -258,7 +259,7 @@
if (info.agent.isManagingTrust()) {
trustMayHaveChanged = true;
}
- info.agent.unbind();
+ info.agent.destroy();
mActiveAgents.remove(info);
}
}
@@ -290,7 +291,7 @@
if (info.agent.isManagingTrust()) {
trustMayHaveChanged = true;
}
- info.agent.unbind();
+ info.agent.destroy();
mActiveAgents.removeAt(i);
}
}
@@ -308,7 +309,7 @@
if (info.agent.isManagingTrust()) {
trustMayHaveChanged = true;
}
- info.agent.unbind();
+ info.agent.destroy();
mActiveAgents.removeAt(i);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 82e4bb1..a90cc95 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -21,6 +21,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
@@ -241,6 +242,7 @@
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
winAnimator.mAnimationIsEntrance = false;
+ winAnimator.mAnimationStartTime = -1;
}
} else {
if (DEBUG_KEYGUARD) Slog.d(TAG,
@@ -263,6 +265,7 @@
null : winShowWhenLocked.mAppToken;
boolean wallpaperInUnForceHiding = false;
+ boolean startingInUnForceHiding = false;
ArrayList<WindowStateAnimator> unForceHiding = null;
WindowState wallpaper = null;
for (int i = windows.size() - 1; i >= 0; i--) {
@@ -344,8 +347,14 @@
if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
"Now policy hidden: " + win);
} else {
- if (!win.showLw(false, false)) {
- // Was already showing.
+ boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null
+ && !winAnimator.mKeyguardGoingAwayAnimation
+ && win.hasDrawnLw()
+ && win.mAttachedWindow == null;
+
+ // If the window is already showing and we don't need to apply an existing
+ // Keyguard exit animation, skip.
+ if (!win.showLw(false, false) && !applyExistingExitAnimation) {
continue;
}
final boolean visibleNow = win.isVisibleNow();
@@ -356,7 +365,8 @@
}
if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
"Now policy shown: " + win);
- if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+ if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
+ && win.mAttachedWindow == null) {
if (unForceHiding == null) {
unForceHiding = new ArrayList<>();
}
@@ -364,11 +374,19 @@
if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
wallpaperInUnForceHiding = true;
}
- } else if (mPostKeyguardExitAnimation != null) {
+ if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
+ startingInUnForceHiding = true;
+ }
+ } else if (applyExistingExitAnimation) {
// We're already in the middle of an animation. Use the existing
// animation to bring in this window.
- winAnimator.setAnimation(mPostKeyguardExitAnimation);
- winAnimator.keyguardGoingAwayAnimation = true;
+ if (DEBUG_KEYGUARD) Slog.v(TAG,
+ "Applying existing Keyguard exit animation to new window: win="
+ + win);
+ Animation a = mPolicy.createForceHideEnterAnimation(
+ false, mKeyguardGoingAwayToNotificationShade);
+ winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
+ winAnimator.mKeyguardGoingAwayAnimation = true;
}
final WindowState currentFocus = mService.mCurrentFocus;
if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
@@ -421,25 +439,34 @@
} // end forall windows
// If we have windows that are being show due to them no longer
- // being force-hidden, apply the appropriate animation to them.
+ // being force-hidden, apply the appropriate animation to them if animations are not
+ // disabled.
if (unForceHiding != null) {
- // This only happens the first time that we detect the keyguard is animating out.
- if (mKeyguardGoingAwayDisableWindowAnimations) {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for windows");
- } else {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim for windows="
- + unForceHiding);
- mPostKeyguardExitAnimation = mPolicy.createForceHideEnterAnimation(
- wallpaperInUnForceHiding, mKeyguardGoingAwayToNotificationShade);
- }
- if (mPostKeyguardExitAnimation != null) {
+ if (!mKeyguardGoingAwayDisableWindowAnimations) {
+ boolean first = true;
for (int i=unForceHiding.size()-1; i>=0; i--) {
final WindowStateAnimator winAnimator = unForceHiding.get(i);
- winAnimator.setAnimation(mPostKeyguardExitAnimation);
- winAnimator.keyguardGoingAwayAnimation = true;
+ Animation a = mPolicy.createForceHideEnterAnimation(
+ wallpaperInUnForceHiding && !startingInUnForceHiding,
+ mKeyguardGoingAwayToNotificationShade);
+ if (a != null) {
+ if (DEBUG_KEYGUARD) Slog.v(TAG,
+ "Starting keyguard exit animation on window " + winAnimator.mWin);
+ winAnimator.setAnimation(a);
+ winAnimator.mKeyguardGoingAwayAnimation = true;
+ if (first) {
+ mPostKeyguardExitAnimation = a;
+ mPostKeyguardExitAnimation.setStartTime(mCurrentTime);
+ first = false;
+ }
+ }
}
+ } else if (mKeyguardGoingAway) {
+ mPolicy.startKeyguardExitAnimation(mCurrentTime, 0 /* duration */);
+ mKeyguardGoingAway = false;
}
+
// Wallpaper is going away in un-force-hide motion, animate it as well.
if (!wallpaperInUnForceHiding && wallpaper != null
&& !mKeyguardGoingAwayDisableWindowAnimations) {
@@ -459,8 +486,10 @@
mPostKeyguardExitAnimation.getStartOffset(),
mPostKeyguardExitAnimation.getDuration());
mKeyguardGoingAway = false;
- } else if (mPostKeyguardExitAnimation.hasEnded()) {
+ } else if (mCurrentTime - mPostKeyguardExitAnimation.getStartTime()
+ > mPostKeyguardExitAnimation.getDuration()) {
// Done with the animation, reset.
+ if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
mPostKeyguardExitAnimation = null;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6cb1e4a..1e492a5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1759,7 +1759,7 @@
// wallpaper during the animation so it doesn't flicker out.
final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
|| (w.mAppToken != null
- && w.mWinAnimator.keyguardGoingAwayAnimation);
+ && w.mWinAnimator.mKeyguardGoingAwayAnimation);
if (hasWallpaper && w.isOnScreen()
&& (mWallpaperTarget == w || w.isDrawFinishedLw())) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
@@ -2541,8 +2541,8 @@
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
- if (true || localLOGV) Slog.v(TAG, "addWindow: New client " + client.asBinder()
- + ": window=" + win + " Callers=" + Debug.getCallers(5));
+ if (true || localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client "
+ + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
reportNewConfig = true;
@@ -5411,7 +5411,7 @@
public void notifyActivityDrawnForKeyguard() {
if (DEBUG_KEYGUARD) Slog.d(TAG, "notifyActivityDrawnForKeyguard: waiting="
- + mKeyguardWaitingForActivityDrawn);
+ + mKeyguardWaitingForActivityDrawn + " Callers=" + Debug.getCallers(5));
synchronized (mWindowMap) {
if (mKeyguardWaitingForActivityDrawn) {
mPolicy.notifyActivityDrawnForKeyguardLw();
@@ -9322,6 +9322,7 @@
}
updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
mFocusMayChange = false;
+ notifyActivityDrawnForKeyguard();
}
return changes;
@@ -9809,7 +9810,8 @@
atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
atoken.startingDisplayed = false;
}
- if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
+ if ((w.isOnScreenIgnoringKeyguard()
+ || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
&& !w.mExiting && !w.mDestroying) {
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f9efc80..021a6e4 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -935,7 +935,15 @@
* being visible.
*/
boolean isOnScreen() {
- if (!mHasSurface || !mPolicyVisibility || mDestroying) {
+ return mPolicyVisibility && isOnScreenIgnoringKeyguard();
+ }
+
+ /**
+ * Like isOnScreen(), but ignores any force hiding of the window due
+ * to the keyguard.
+ */
+ boolean isOnScreenIgnoringKeyguard() {
+ if (!mHasSurface || mDestroying) {
return false;
}
final AppWindowToken atoken = mAppToken;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 819ca50..87d420f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -53,10 +53,13 @@
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
+import com.android.internal.R;
import com.android.server.wm.WindowManagerService.H;
import java.io.PrintWriter;
@@ -97,6 +100,8 @@
boolean mWasAnimating; // Were we animating going into the most recent animation step?
int mAnimLayer;
int mLastLayer;
+ long mAnimationStartTime;
+ long mLastAnimationTime;
SurfaceControl mSurfaceControl;
SurfaceControl mPendingDestroySurface;
@@ -147,7 +152,7 @@
* window is first added or shown, cleared when the callback has been made. */
boolean mEnteringAnimation;
- boolean keyguardGoingAwayAnimation;
+ boolean mKeyguardGoingAwayAnimation;
/** This is set when there is no Surface */
static final int NO_SURFACE = 0;
@@ -210,7 +215,7 @@
mIsWallpaper = win.mIsWallpaper;
}
- public void setAnimation(Animation anim) {
+ public void setAnimation(Animation anim, long startTime) {
if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
mLocalAnimating = false;
@@ -221,6 +226,11 @@
mTransformation.clear();
mTransformation.setAlpha(mLastHidden ? 0 : 1);
mHasLocalTransformation = true;
+ mAnimationStartTime = startTime;
+ }
+
+ public void setAnimation(Animation anim) {
+ setAnimation(anim, -1);
}
public void clearAnimation() {
@@ -229,7 +239,7 @@
mLocalAnimating = false;
mAnimation.cancel();
mAnimation = null;
- keyguardGoingAwayAnimation = false;
+ mKeyguardGoingAwayAnimation = false;
}
}
@@ -299,11 +309,14 @@
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
mAnimDw = displayInfo.appWidth;
mAnimDh = displayInfo.appHeight;
- mAnimation.setStartTime(currentTime);
+ mAnimation.setStartTime(mAnimationStartTime != -1
+ ? mAnimationStartTime
+ : currentTime);
mLocalAnimating = true;
mAnimating = true;
}
if ((mAnimation != null) && mLocalAnimating) {
+ mLastAnimationTime = currentTime;
if (stepAnimation(currentTime)) {
return true;
}
@@ -351,7 +364,7 @@
+ (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
mAnimating = false;
- keyguardGoingAwayAnimation = false;
+ mKeyguardGoingAwayAnimation = false;
mLocalAnimating = false;
if (mAnimation != null) {
mAnimation.cancel();
@@ -500,9 +513,6 @@
Slog.v(TAG, "Draw state now committed in " + mWin);
}
mDrawState = COMMIT_DRAW_PENDING;
- if (startingWindow) {
- mService.notifyActivityDrawnForKeyguard();
- }
return true;
}
return false;
@@ -1786,9 +1796,17 @@
* @return true if an animation has been loaded.
*/
boolean applyAnimationLocked(int transit, boolean isEntrance) {
- if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+ if ((mLocalAnimating && mAnimationIsEntrance == isEntrance)
+ || mKeyguardGoingAwayAnimation) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
+
+ // If we are in a keyguard exit animation, and the window should animate away, modify
+ // keyguard exit animation such that it also fades out.
+ if (mAnimation != null && mKeyguardGoingAwayAnimation
+ && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) {
+ applyFadeoutDuringKeyguardExitAnimation();
+ }
return true;
}
@@ -1846,6 +1864,28 @@
return mAnimation != null;
}
+ private void applyFadeoutDuringKeyguardExitAnimation() {
+ long startTime = mAnimation.getStartTime();
+ long duration = mAnimation.getDuration();
+ long elapsed = mLastAnimationTime - startTime;
+ long fadeDuration = duration - elapsed;
+ if (fadeDuration <= 0) {
+ // Never mind, this would be no visible animation, so abort the animation change.
+ return;
+ }
+ AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */);
+ newAnimation.setDuration(duration);
+ newAnimation.setStartTime(startTime);
+ newAnimation.addAnimation(mAnimation);
+ Animation fadeOut = AnimationUtils.loadAnimation(
+ mContext, com.android.internal.R.anim.app_starting_exit);
+ fadeOut.setDuration(fadeDuration);
+ fadeOut.setStartOffset(elapsed);
+ newAnimation.addAnimation(fadeOut);
+ newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDw, mAnimDh);
+ mAnimation = newAnimation;
+ }
+
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
if (mAnimating || mLocalAnimating || mAnimationIsEntrance
|| mAnimation != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d7f6130..4e6a8ea 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -147,7 +147,6 @@
private SystemServiceManager mSystemServiceManager;
// TODO: remove all of these references by improving dependency resolution and boot phases
- private Installer mInstaller;
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
private DisplayManagerService mDisplayManagerService;
@@ -309,12 +308,13 @@
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
- mInstaller = mSystemServiceManager.startService(Installer.class);
+ Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
+ mActivityManagerService.setInstaller(installer);
// Power manager needs to be started early because other services need it.
// Native daemons may be watching for it to be registered so it must be ready
@@ -345,7 +345,7 @@
// Start the package manager.
Slog.i(TAG, "Package Manager");
- mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
+ mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 853d843..84da72c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -353,9 +353,9 @@
/**
* @hide
- * last time we connected, this configuration had no internet access
+ * last time we connected, this configuration had validated internet access
*/
- public boolean noInternetAccess;
+ public boolean validatedInternetAccess;
/**
* @hide
@@ -687,6 +687,22 @@
/**
* @hide
+ * Number of reports indicating no Internet Access
+ */
+ public int numNoInternetAccessReports;
+
+ /**
+ * @hide
+ * The WiFi configuration is considered to have no internet access for purpose of autojoining
+ * if there has been a report of it having no internet access, and, it never have had
+ * internet access in the past.
+ */
+ public boolean hasNoInternetAccess() {
+ return numNoInternetAccessReports > 0 && !validatedInternetAccess;
+ }
+
+ /**
+ * @hide
* Last time we blacklisted the configuration
*/
public long blackListTimestamp;
@@ -872,7 +888,7 @@
selfAdded = false;
didSelfAdd = false;
ephemeral = false;
- noInternetAccess = false;
+ validatedInternetAccess = false;
mIpConfiguration = new IpConfiguration();
lastUpdateUid = -1;
creatorUid = -1;
@@ -1030,11 +1046,15 @@
if (this.numAssociation > 0) {
sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
}
+ if (this.numNoInternetAccessReports > 0) {
+ sbuf.append(" numNoInternetAccessReports ");
+ sbuf.append(this.numNoInternetAccessReports).append("\n");
+ }
if (this.didSelfAdd) sbuf.append(" didSelfAdd");
if (this.selfAdded) sbuf.append(" selfAdded");
- if (this.noInternetAccess) sbuf.append(" noInternetAccess");
+ if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
- if (this.didSelfAdd || this.selfAdded || this.noInternetAccess || this.ephemeral) {
+ if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess || this.ephemeral) {
sbuf.append("\n");
}
sbuf.append(" KeyMgmt:");
@@ -1509,7 +1529,7 @@
mCachedConfigKey = null; //force null configKey
autoJoinStatus = source.autoJoinStatus;
selfAdded = source.selfAdded;
- noInternetAccess = source.noInternetAccess;
+ validatedInternetAccess = source.validatedInternetAccess;
ephemeral = source.ephemeral;
if (source.visibility != null) {
visibility = new Visibility(source.visibility);
@@ -1546,6 +1566,7 @@
autoJoinBailedDueToLowRssi = source.autoJoinBailedDueToLowRssi;
dirty = source.dirty;
userApproved = source.userApproved;
+ numNoInternetAccessReports = source.numNoInternetAccessReports;
}
}
@@ -1589,7 +1610,7 @@
dest.writeInt(autoJoinStatus);
dest.writeInt(selfAdded ? 1 : 0);
dest.writeInt(didSelfAdd ? 1 : 0);
- dest.writeInt(noInternetAccess ? 1 : 0);
+ dest.writeInt(validatedInternetAccess ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
@@ -1614,6 +1635,7 @@
dest.writeInt(autoJoinUseAggressiveJoinAttemptThreshold);
dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0);
dest.writeInt(userApproved);
+ dest.writeInt(numNoInternetAccessReports);
}
/** Implement the Parcelable interface {@hide} */
@@ -1653,7 +1675,7 @@
config.autoJoinStatus = in.readInt();
config.selfAdded = in.readInt() != 0;
config.didSelfAdd = in.readInt() != 0;
- config.noInternetAccess = in.readInt() != 0;
+ config.validatedInternetAccess = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
@@ -1678,6 +1700,7 @@
config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
config.userApproved = in.readInt();
+ config.numNoInternetAccessReports = in.readInt();
return config;
}