diff options
28 files changed, 575 insertions, 74 deletions
@@ -160,6 +160,7 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \ core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \ core/java/android/hardware/fingerprint/IFingerprintService.aidl \ + core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \ core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \ core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \ core/java/android/hardware/hdmi/IHdmiControlService.aidl \ diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 3b026d2..132ffef 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -2196,6 +2196,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate fragment.mTag = tag; fragment.mInLayout = true; fragment.mFragmentManager = this; + fragment.mHost = mHost; fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState); addFragment(fragment, true); } else if (fragment.mInLayout) { diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 7cff11b..1f23c0a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -392,6 +392,18 @@ public class FingerprintManager { }; /** + * @hide + */ + public static abstract class LockoutResetCallback { + + /** + * Called when lockout period expired and clients are allowed to listen for fingerprint + * again. + */ + public void onLockoutReset() { } + }; + + /** * Request authentication of a crypto object. This call warms up the fingerprint hardware * and starts scanning for a fingerprint. It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or @@ -680,10 +692,37 @@ public class FingerprintManager { try { mService.resetTimeout(token); } catch (RemoteException e) { - Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e); + Log.v(TAG, "Remote exception in resetTimeout(): ", e); } } else { - Log.w(TAG, "getAuthenticatorId(): Service not connected!"); + Log.w(TAG, "resetTimeout(): Service not connected!"); + } + } + + /** + * @hide + */ + public void addLockoutResetCallback(final LockoutResetCallback callback) { + if (mService != null) { + try { + mService.addLockoutResetCallback( + new IFingerprintServiceLockoutResetCallback.Stub() { + + @Override + public void onLockoutReset(long deviceId) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + callback.onLockoutReset(); + } + }); + } + }); + } catch (RemoteException e) { + Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e); + } + } else { + Log.w(TAG, "addLockoutResetCallback(): Service not connected!"); } } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 3356354..690a751 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -17,6 +17,7 @@ package android.hardware.fingerprint; import android.os.Bundle; import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.hardware.fingerprint.Fingerprint; import java.util.List; @@ -71,4 +72,7 @@ interface IFingerprintService { // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password) void resetTimeout(in byte [] cryptoToken); + + // Add a callback which gets notified when the fingerprint lockout period expired. + void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl new file mode 100644 index 0000000..c9a5d59 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.fingerprint; + +import android.hardware.fingerprint.Fingerprint; +import android.os.Bundle; +import android.os.UserHandle; + +/** + * Callback when lockout period expired and clients are allowed to authenticate again. + * @hide + */ +oneway interface IFingerprintServiceLockoutResetCallback { + void onLockoutReset(long deviceId); +} diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index d24b10b..a3a01da 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1174,7 +1174,7 @@ public class LockPatternUtils { * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} */ public void requireCredentialEntry(int userId) { - requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId); + requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId); } /** @@ -1251,7 +1251,7 @@ public class LockPatternUtils { value = { STRONG_AUTH_NOT_REQUIRED, STRONG_AUTH_REQUIRED_AFTER_BOOT, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, - SOME_AUTH_REQUIRED_AFTER_USER_REQUEST}) + STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST}) @Retention(RetentionPolicy.SOURCE) public @interface StrongAuthFlags {} @@ -1266,14 +1266,14 @@ public class LockPatternUtils { public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1; /** - * Strong authentication is required because a device admin has requested it. + * Strong authentication is required because a device admin has temporarily requested it. */ public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2; /** - * Some authentication is required because the user has temporarily disabled trust. + * Strong authentication is required because the user has temporarily requested it. */ - public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4; + public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4; /** * Strong authentication is required because the user has been locked out after too many @@ -1282,7 +1282,6 @@ public class LockPatternUtils { public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8; public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT; - private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray(); @@ -1324,7 +1323,7 @@ public class LockPatternUtils { * current strong authentication requirements. */ public boolean isFingerprintAllowedForUser(int userId) { - return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0; + return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED; } /** diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 4c920dc..b431a3f 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -83,6 +83,14 @@ static void SigChldHandler(int /*signal_number*/) { pid_t pid; int status; + // It's necessary to save and restore the errno during this function. + // Since errno is stored per thread, changing it here modifies the errno + // on the thread on which this signal handler executes. If a signal occurs + // between a call and an errno check, it's possible to get the errno set + // here. + // See b/23572286 for extra information. + int saved_errno = errno; + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { // Log process-death status that we care about. In general it is // not safe to call LOG(...) from a signal handler because of @@ -118,6 +126,8 @@ static void SigChldHandler(int /*signal_number*/) { if (pid < 0 && errno != ECHILD) { ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno)); } + + errno = saved_errno; } // Configures the SIGCHLD handler for the zygote process. This is configured diff --git a/core/res/res/values-mcc204-mnc12/config.xml b/core/res/res/values-mcc204-mnc12/config.xml new file mode 100644 index 0000000..80432d7 --- /dev/null +++ b/core/res/res/values-mcc204-mnc12/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2015, 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 my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>20408</item> + </string-array> +</resources> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java index ce2d11a..f51e10f 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -64,7 +64,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView @Override protected void resetState() { - mPasswordEntry.setEnabled(true); + setPasswordEntryEnabled(true); } @Override diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index fc6117f..cfc232c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; @@ -472,6 +473,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + private void handleFingerprintLockoutReset() { + updateFingerprintListeningState(); + } + private void setFingerprintRunningState(int fingerprintRunningState) { boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING; boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING; @@ -681,6 +686,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } }; + private final FingerprintManager.LockoutResetCallback mLockoutResetCallback + = new FingerprintManager.LockoutResetCallback() { + @Override + public void onLockoutReset() { + handleFingerprintLockoutReset(); + } + }; + private FingerprintManager.AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { @@ -1003,6 +1016,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); updateFingerprintListeningState(); + if (mFpm != null) { + mFpm.addLockoutResetCallback(mLockoutResetCallback); + } } private void updateFingerprintListeningState() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index c14f215..eecac63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1636,11 +1636,13 @@ public abstract class BaseStatusBar extends SystemUI implements protected void handleVisibleToUserChanged(boolean visibleToUser) { try { if (visibleToUser) { - boolean clearNotificationEffects = !isPanelFullyCollapsed() && - (mShowLockscreenNotifications || - (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED)); + boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp(); + boolean clearNotificationEffects = + ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) || + (!pinnedHeadsUp && (mState == StatusBarState.SHADE + || mState == StatusBarState.SHADE_LOCKED))); int notificationLoad = mNotificationData.getActiveNotifications().size(); - if (mHeadsUpManager.hasPinnedHeadsUp() && isPanelFullyCollapsed()) { + if (pinnedHeadsUp && isPanelFullyCollapsed()) { notificationLoad = 1; } else { MetricsLogger.histogram(mContext, "note_load", notificationLoad); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index d30411a..f4439bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -262,14 +262,21 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; } + /** + * Resolves the intent to launch the camera application. + */ + public ResolveInfo resolveCameraIntent() { + return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), + PackageManager.MATCH_DEFAULT_ONLY, + KeyguardUpdateMonitor.getCurrentUser()); + } + private void updateCameraVisibility() { if (mCameraImageView == null) { // Things are not set up yet; reply hazy, ask again later return; } - ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), - PackageManager.MATCH_DEFAULT_ONLY, - KeyguardUpdateMonitor.getCurrentUser()); + ResolveInfo resolved = resolveCameraIntent(); boolean visible = !isCameraDisabledByDpm() && resolved != null && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance) && mUserSetupComplete; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java index 93ecb06..d0a7f8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -166,10 +166,13 @@ public class LockIcon extends KeyguardAffordanceView { if (mAccessibilityController == null) { return; } + boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged() + || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed(); + boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled(); - boolean clickToForceLock = mUnlockMethodCache.isTrustManaged() + boolean clickToForceLock = trustManagedOrFingerprintAllowed && !mAccessibilityController.isAccessibilityEnabled(); - boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged() + boolean longClickToForceLock = trustManagedOrFingerprintAllowed && !clickToForceLock; setClickable(clickToForceLock || clickToUnlock); setLongClickable(longClickToForceLock); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java index 950b162..310625e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java @@ -78,6 +78,13 @@ public class NotificationGroupManager { Notification notif = sbn.getNotification(); String groupKey = sbn.getGroupKey(); final NotificationGroup group = mGroupMap.get(groupKey); + if (group == null) { + // When an app posts 2 different notifications as summary of the same group, then a + // cancellation of the first notification removes this group. + // This situation is not supported and we will not allow such notifications anymore in + // the close future. See b/23676310 for reference. + return; + } if (notif.isGroupSummary()) { group.summary = null; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 5557f9c..b93586e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -21,7 +21,10 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; +import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; @@ -61,6 +64,8 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; +import java.util.List; + public class NotificationPanelView extends PanelView implements ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener, View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, @@ -2425,7 +2430,28 @@ public class NotificationPanelView extends PanelView implements getCenterIcon().setLaunchingAffordance(launchingAffordance); } - public boolean canCameraGestureBeLaunched() { - return !mAfforanceHelper.isSwipingInProgress(); + /** + * Whether the camera application can be launched for the camera launch gesture. + * + * @param keyguardIsShowing whether keyguard is being shown + */ + public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) { + ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent(); + String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null) + ? null : resolveInfo.activityInfo.packageName; + return packageToLaunch != null && + (keyguardIsShowing || !isForegroundApp(packageToLaunch)) && + !mAfforanceHelper.isSwipingInProgress(); + } + + /** + * Return true if the applications with the package name is running in foreground. + * + * @param pkgName application package name. + */ + private boolean isForegroundApp(String pkgName) { + ActivityManager am = getContext().getSystemService(ActivityManager.class); + List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); + return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); } } 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 8063bbe..55b1127 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -3742,12 +3742,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // down on the lockscreen), clear notification LED, vibration, // ringing. // Other transitions are covered in handleVisibleToUserChanged(). - if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) { - try { - mBarService.clearNotificationEffects(); - } catch (RemoteException e) { - // Ignore. - } + if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED + || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) { + clearNotificationEffects(); } mState = state; mGroupManager.setStatusBarState(state); @@ -4090,7 +4087,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void onCameraLaunchGestureDetected() { - if (!mNotificationPanel.canCameraGestureBeLaunched()) { + if (!mNotificationPanel.canCameraGestureBeLaunched( + mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) { return; } if (!mDeviceInteractive) { diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index d58d372..e3d5d38 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -177,7 +177,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; - private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000; + private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY; private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 191bf99..3738d1e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -400,6 +400,17 @@ public final class ActivityManagerService extends ActivityManagerNative private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; + + // Delay to disable app launch boost + static final int APP_BOOST_MESSAGE_DELAY = 3000; + // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost + static final int APP_BOOST_TIMEOUT = 2500; + + private static native int nativeMigrateToBoost(); + private static native int nativeMigrateFromBoost(); + private boolean mIsBoosted = false; + private long mBoostStartTime = 0; + /** All system services */ SystemServiceManager mSystemServiceManager; @@ -1356,6 +1367,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int REPORT_TIME_TRACKER_MSG = 55; static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56; static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57; + static final int APP_BOOST_DEACTIVATE_MSG = 58; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -2031,6 +2043,20 @@ public final class ActivityManagerService extends ActivityManagerNative // it is finished we make sure it is reset to its default. mUserIsMonkey = false; } break; + case APP_BOOST_DEACTIVATE_MSG : { + synchronized(ActivityManagerService.this) { + if (mIsBoosted) { + if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) { + nativeMigrateFromBoost(); + mIsBoosted = false; + mBoostStartTime = 0; + } else { + Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG); + mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT); + } + } + } + } break; } } }; @@ -3114,6 +3140,16 @@ public final class ActivityManagerService extends ActivityManagerNative app = null; } + // app launch boost for big.little configurations + // use cpusets to migrate freshly launched tasks to big cores + synchronized(ActivityManagerService.this) { + nativeMigrateToBoost(); + mIsBoosted = true; + mBoostStartTime = SystemClock.uptimeMillis(); + Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG); + mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY); + } + // We don't have to do anything more if: // (1) There is an existing application record; and // (2) The caller doesn't think it is dead, OR there is no thread diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index a956c56..960cbf1 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -509,7 +509,7 @@ public final class BroadcastQueue { break; } int appOp = AppOpsManager.permissionToOpCode(requiredPermission); - if (appOp != r.appOp + if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp && mService.mAppOpsService.noteOperation(appOp, filter.receiverList.uid, filter.packageName) != AppOpsManager.MODE_ALLOWED) { diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 7e46db8..67c9ee8 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -18,13 +18,18 @@ package com.android.server.fingerprint; import android.Manifest; import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManagerNative; import android.app.AppOpsManager; import android.app.IUserSwitchObserver; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.os.Binder; +import android.os.DeadObjectException; import android.os.Environment; import android.os.Handler; import android.os.IBinder; @@ -51,8 +56,8 @@ import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IFingerprintDaemon; import android.hardware.fingerprint.IFingerprintDaemonCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; -import android.view.Display; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; import static android.Manifest.permission.USE_FINGERPRINT; @@ -60,6 +65,7 @@ import static android.Manifest.permission.USE_FINGERPRINT; import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -83,12 +89,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe private ClientMonitor mAuthClient = null; private ClientMonitor mEnrollClient = null; private ClientMonitor mRemoveClient = null; + private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors = + new ArrayList<>(); private final AppOpsManager mAppOps; private static final long MS_PER_SEC = 1000; private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; private static final int MAX_FAILED_ATTEMPTS = 5; private static final int FINGERPRINT_ACQUIRED_GOOD = 0; + private final String mKeyguardPackage; Handler mHandler = new Handler() { @Override @@ -121,6 +130,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe public FingerprintService(Context context) { super(context); mContext = context; + mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString( + com.android.internal.R.string.config_keyguardComponent)).getPackageName(); mAppOps = context.getSystemService(AppOpsManager.class); mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); } @@ -259,6 +270,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable // may still be in the queue; remove it. mHandler.removeCallbacks(mLockoutReset); + notifyLockoutResetMonitors(); } private boolean handleFailedAttempt(ClientMonitor clientMonitor) { @@ -493,10 +505,67 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe return false; } - private boolean canUseFingerprint(String opPackageName) { + private boolean isForegroundActivity(int uid, int pid) { + try { + List<RunningAppProcessInfo> procs = + ActivityManagerNative.getDefault().getRunningAppProcesses(); + int N = procs.size(); + for (int i = 0; i < N; i++) { + RunningAppProcessInfo proc = procs.get(i); + if (proc.pid == pid && proc.uid == uid + && proc.importance == IMPORTANCE_FOREGROUND) { + return true; + } + } + } catch (RemoteException e) { + Slog.w(TAG, "am.getRunningAppProcesses() failed"); + } + return false; + } + + /** + * @param opPackageName name of package for caller + * @param foregroundOnly only allow this call while app is in the foreground + * @return true if caller can use fingerprint API + */ + private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) { checkPermission(USE_FINGERPRINT); - return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(), - opPackageName) == AppOpsManager.MODE_ALLOWED; + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); + if (opPackageName.equals(mKeyguardPackage)) { + return true; // Keyguard is always allowed + } + if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { + Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile"); + return false; + } + if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied"); + return false; + } + if (foregroundOnly && !isForegroundActivity(uid, pid)) { + Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground"); + return false; + } + return true; + } + + private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) { + if (!mLockoutMonitors.contains(monitor)) { + mLockoutMonitors.add(monitor); + } + } + + private void removeLockoutResetCallback( + FingerprintServiceLockoutResetMonitor monitor) { + mLockoutMonitors.remove(monitor); + } + + private void notifyLockoutResetMonitors() { + for (int i = 0; i < mLockoutMonitors.size(); i++) { + mLockoutMonitors.get(i).sendLockoutReset(); + } } private class ClientMonitor implements IBinder.DeathRecipient { @@ -614,7 +683,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe FingerprintUtils.vibrateFingerprintSuccess(getContext()); } result |= true; // we have a valid fingerprint - mLockoutReset.run(); + mHandler.post(mLockoutReset); } return result; } @@ -654,6 +723,36 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } } + private class FingerprintServiceLockoutResetMonitor { + + private final IFingerprintServiceLockoutResetCallback mCallback; + + public FingerprintServiceLockoutResetMonitor( + IFingerprintServiceLockoutResetCallback callback) { + mCallback = callback; + } + + public void sendLockoutReset() { + if (mCallback != null) { + try { + mCallback.onLockoutReset(mHalDeviceId); + } catch (DeadObjectException e) { + Slog.w(TAG, "Death object while invoking onLockoutReset: ", e); + mHandler.post(mRemoveCallbackRunnable); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to invoke onLockoutReset: ", e); + } + } + } + + private final Runnable mRemoveCallbackRunnable = new Runnable() { + @Override + public void run() { + removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this); + } + }; + } + private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { @Override @@ -782,12 +881,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName) { - if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) { - Slog.w(TAG, "Can't authenticate non-current user"); - return; - } - if (!canUseFingerprint(opPackageName)) { - Slog.w(TAG, "Calling not granted permission to use fingerprint"); + if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) { return; } @@ -807,7 +901,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public void cancelAuthentication(final IBinder token, String opPackageName) { - if (!canUseFingerprint(opPackageName)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { return; } mHandler.post(new Runnable() { @@ -838,7 +932,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public boolean isHardwareDetected(long deviceId, String opPackageName) { - if (!canUseFingerprint(opPackageName)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { return false; } return mHalDeviceId != 0; @@ -862,7 +956,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) { - if (!canUseFingerprint(opPackageName)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { return Collections.emptyList(); } int effectiveUserId = getEffectiveUserId(userId); @@ -872,7 +966,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public boolean hasEnrolledFingerprints(int userId, String opPackageName) { - if (!canUseFingerprint(opPackageName)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { return false; } @@ -922,7 +1016,19 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe public void resetTimeout(byte [] token) { checkPermission(RESET_FINGERPRINT_LOCKOUT); // TODO: confirm security token when we move timeout management into the HAL layer. - mLockoutReset.run(); + mHandler.post(mLockoutReset); + } + + @Override + public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback) + throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + addLockoutResetMonitor( + new FingerprintServiceLockoutResetMonitor(callback)); + } + }); } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index d7c9c02..34737c1 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4417,7 +4417,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mAppsToBeHidden.isEmpty()) { if (dismissKeyguard && !mKeyguardSecure) { mAppsThatDismissKeyguard.add(appToken); - } else if (win.isDrawnLw()) { + } else if (win.isDrawnLw() || win.hasAppShownWindows()) { mWinShowWhenLocked = win; mHideLockScreen = true; mForceStatusBarFromKeyguard = false; @@ -4451,7 +4451,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWinDismissingKeyguard = win; mSecureDismissingKeyguard = mKeyguardSecure; mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure; - } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) { + } else if (mAppsToBeHidden.isEmpty() && showWhenLocked + && (win.isDrawnLw() || win.hasAppShownWindows())) { if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); mHideLockScreen = true; diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 794b49c..985bbfb 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -375,7 +375,10 @@ public class TaskStack { for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) { final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows; for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { - mService.removeWindowInnerLocked(appWindows.get(winNdx)); + // We are in the middle of changing the state of displays/stacks/tasks. We need + // to finish that, before we let layout interfere with it. + mService.removeWindowInnerLocked(appWindows.get(winNdx), + false /* performLayout */); doAnotherLayoutPass = true; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 36cb7f2..e903e4f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2793,6 +2793,10 @@ public class WindowManagerService extends IWindowManager.Stub } void removeWindowInnerLocked(WindowState win) { + removeWindowInnerLocked(win, true); + } + + void removeWindowInnerLocked(WindowState win, boolean performLayout) { if (win.mRemoved) { // Nothing to do. return; @@ -2890,7 +2894,9 @@ public class WindowManagerService extends IWindowManager.Stub if (displayContent != null) { displayContent.layoutNeeded = true; } - performLayoutAndPlaceSurfacesLocked(); + if (performLayout) { + performLayoutAndPlaceSurfacesLocked(); + } if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); } @@ -5193,7 +5199,9 @@ public class WindowManagerService extends IWindowManager.Stub } public void removeStack(int stackId) { - mStackIdToStack.remove(stackId); + synchronized (mWindowMap) { + mStackIdToStack.remove(stackId); + } } public void removeTask(int taskId) { @@ -5267,10 +5275,12 @@ public class WindowManagerService extends IWindowManager.Stub } public void getStackBounds(int stackId, Rect bounds) { - final TaskStack stack = mStackIdToStack.get(stackId); - if (stack != null) { - stack.getBounds(bounds); - return; + synchronized (mWindowMap) { + final TaskStack stack = mStackIdToStack.get(stackId); + if (stack != null) { + stack.getBounds(bounds); + return; + } } bounds.setEmpty(); } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 9556b08..98d8d08 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -4,9 +4,16 @@ LOCAL_REL_DIR := core/jni LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter +ifneq ($(ENABLE_CPUSETS),) +ifneq ($(ENABLE_SCHED_BOOST),) +LOCAL_CFLAGS += -DUSE_SCHED_BOOST +endif +endif + LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp new file mode 100644 index 0000000..52217b9 --- /dev/null +++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015 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. + */ + +#define LOG_TAG "ActivityManagerService" +//#define LOG_NDEBUG 0 + +#include <android_runtime/AndroidRuntime.h> +#include <jni.h> + +#include <ScopedLocalRef.h> +#include <ScopedPrimitiveArray.h> + +#include <cutils/log.h> +#include <utils/misc.h> +#include <utils/Log.h> + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +namespace android +{ + + // migrate from foreground to foreground_boost + static jint migrateToBoost(JNIEnv *env, jobject _this) + { +#ifdef USE_SCHED_BOOST + // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error + FILE* fg_cpuset_file = NULL; + int boost_cpuset_fd = 0; + if (!access("/dev/cpuset/tasks", F_OK)) { + fg_cpuset_file = fopen("/dev/cpuset/foreground/tasks", "r+"); + if (ferror(fg_cpuset_file)) { + return 0; + } + boost_cpuset_fd = open("/dev/cpuset/foreground/boost/tasks", O_WRONLY); + if (boost_cpuset_fd < 0) { + fclose(fg_cpuset_file); + return 0; + } + + } + if (!fg_cpuset_file || !boost_cpuset_fd) { + fclose(fg_cpuset_file); + close(boost_cpuset_fd); + return 0; + } + char buf[17]; + while (fgets(buf, 16, fg_cpuset_file)) { + int i = 0; + for (; i < 16; i++) { + if (buf[i] == '\n') { + buf[i] = 0; + break; + } + } + if (write(boost_cpuset_fd, buf, i) < 0) { + // ignore error + } + if (feof(fg_cpuset_file)) + break; + } + fclose(fg_cpuset_file); + close(boost_cpuset_fd); +#endif + return 0; + } + + // migrate from foreground_boost to foreground + static jint migrateFromBoost(JNIEnv *env, jobject _this) + { +#ifdef USE_SCHED_BOOST + // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error + int fg_cpuset_fd = 0; + FILE* boost_cpuset_file = NULL; + if (!access("/dev/cpuset/tasks", F_OK)) { + boost_cpuset_file = fopen("/dev/cpuset/foreground/boost/tasks", "r+"); + if (ferror(boost_cpuset_file)) { + return 0; + } + fg_cpuset_fd = open("/dev/cpuset/foreground/tasks", O_WRONLY); + if (fg_cpuset_fd < 0) { + fclose(boost_cpuset_file); + return 0; + } + + } + if (!boost_cpuset_file || !fg_cpuset_fd) { + fclose(boost_cpuset_file); + close(fg_cpuset_fd); + return 0; + } + char buf[17]; + char *curBuf = buf; + while (fgets(buf, 16, boost_cpuset_file)) { + //ALOGE("Appending FD %s to fg", buf); + int i = 0; + for (; i < 16; i++) { + if (buf[i] == '\n') { + buf[i] = 0; + break; + } + } + if (write(fg_cpuset_fd, buf, i) < 0) { + //ALOGE("Appending FD %s to fg ERROR", buf); + // handle error? + } + if (feof(boost_cpuset_file)) + break; + } + + close(fg_cpuset_fd); + fclose(boost_cpuset_file); + +#endif + return 0; + + } + + + static JNINativeMethod method_table[] = { + { "nativeMigrateToBoost", "()I", (void*)migrateToBoost }, + { "nativeMigrateFromBoost", "()I", (void*)migrateFromBoost }, + }; + + int register_android_server_ActivityManagerService(JNIEnv *env) + { + return jniRegisterNativeMethods(env, "com/android/server/am/ActivityManagerService", + method_table, NELEM(method_table)); + } + +} diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 67872da..1f3fde6 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -20,6 +20,7 @@ #include "utils/misc.h" namespace android { +int register_android_server_ActivityManagerService(JNIEnv* env); int register_android_server_AlarmManagerService(JNIEnv* env); int register_android_server_AssetAtlasService(JNIEnv* env); int register_android_server_BatteryStatsService(JNIEnv* env); @@ -57,6 +58,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) } ALOG_ASSERT(env, "Could not retrieve the env!"); + register_android_server_ActivityManagerService(env); register_android_server_PowerManagerService(env); register_android_server_SerialService(env); register_android_server_InputApplicationHandle(env); @@ -80,5 +82,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_PersistentDataBlockService(env); register_android_server_Watchdog(env); + return JNI_VERSION_1_4; } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 6a0bf64..df8affe 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -404,6 +404,15 @@ public class CarrierConfigManager { public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; + /** + * Determines whether the carrier supports making non-emergency phone calls while the phone is + * in emergency callback mode. Default value is {@code true}, meaning that non-emergency calls + * are allowed in emergency callback mode. + * @hide + */ + public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = + "allow_non_emergency_calls_in_ecm_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -496,6 +505,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_MMS_UA_PROF_TAG_NAME_STRING, "x-wap-profile"); sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, ""); sDefaults.putString(KEY_MMS_USER_AGENT_STRING, ""); + sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true); } /** diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 1f3802e..689e359 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -36,8 +36,8 @@ import com.android.util.Pair; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import android.annotation.Nullable; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -139,8 +139,9 @@ public final class BridgeContext extends Context { private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap; private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace - // cache for TypedArray generated from IStyleResourceValue object - private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache; + // cache for TypedArray generated from StyleResourceValue object + private Map<int[], Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>> + mTypedArrayCache; private BridgeInflater mBridgeInflater; private BridgeContentResolver mContentResolver; @@ -621,31 +622,38 @@ public final class BridgeContext extends Context { } } + // The map is from + // attrs (int[]) -> context's current themes (List<StyleRV>) -> resid (int) -> typed array. if (mTypedArrayCache == null) { - mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>(); - - Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>(); - mTypedArrayCache.put(attrs, map); - - BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs); - map.put(resid, ta); - - return ta; + mTypedArrayCache = new IdentityHashMap<int[], + Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>(); } // get the 2nd map - Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs); - if (map == null) { - map = new HashMap<Integer, BridgeTypedArray>(); - mTypedArrayCache.put(attrs, map); + Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>> map2 = + mTypedArrayCache.get(attrs); + if (map2 == null) { + map2 = new HashMap<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>(); + mTypedArrayCache.put(attrs, map2); + } + + // get the 3rd map + List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes(); + Map<Integer, BridgeTypedArray> map3 = map2.get(currentThemes); + if (map3 == null) { + map3 = new HashMap<Integer, BridgeTypedArray>(); + // Create a copy of the list before adding it to the map. This allows reusing the + // existing list. + currentThemes = new ArrayList<StyleResourceValue>(currentThemes); + map2.put(currentThemes, map3); } - // get the array from the 2nd map - BridgeTypedArray ta = map.get(resid); + // get the array from the 3rd map + BridgeTypedArray ta = map3.get(resid); if (ta == null) { ta = createStyleBasedTypedArray(style, attrs); - map.put(resid, ta); + map3.put(resid, ta); } return ta; |
