diff options
Diffstat (limited to 'packages/SystemUI/src')
35 files changed, 926 insertions, 239 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java new file mode 100644 index 0000000..fc98ec4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java @@ -0,0 +1,80 @@ +/* + * 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 com.android.systemui; + +import android.os.Handler; +import android.os.Looper; +import android.os.StrictMode; +import android.view.Choreographer; + +import java.util.ArrayList; + +/** + * Utility class for methods used to dejank the UI. + */ +public class DejankUtils { + + private static final Choreographer sChoreographer = Choreographer.getInstance(); + private static final Handler sHandler = new Handler(); + + private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>(); + + private static final Runnable sAnimationCallbackRunnable = new Runnable() { + @Override + public void run() { + for (int i = 0; i < sPendingRunnables.size(); i++) { + sHandler.post(sPendingRunnables.get(i)); + } + sPendingRunnables.clear(); + } + }; + + /** + * Executes {@code r} after performTraversals. Use this do to CPU heavy work for which the + * timing is not critical for animation. The work is then scheduled at the same time + * RenderThread is doing its thing, leading to better parallelization. + * + * <p>Needs to be called from the main thread. + */ + public static void postAfterTraversal(Runnable r) { + throwIfNotCalledOnMainThread(); + sPendingRunnables.add(r); + postAnimationCallback(); + } + + /** + * Removes a previously scheduled runnable. + * + * <p>Needs to be called from the main thread. + */ + public static void removeCallbacks(Runnable r) { + throwIfNotCalledOnMainThread(); + sPendingRunnables.remove(r); + sHandler.removeCallbacks(r); + } + + private static void postAnimationCallback() { + sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, sAnimationCallbackRunnable, + null); + } + + private static void throwIfNotCalledOnMainThread() { + if (!Looper.getMainLooper().isCurrentThread()) { + throw new IllegalStateException("should be called from the main thread."); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java index d406f5b..11996d0 100644 --- a/packages/SystemUI/src/com/android/systemui/DemoMode.java +++ b/packages/SystemUI/src/com/android/systemui/DemoMode.java @@ -20,6 +20,8 @@ import android.os.Bundle; public interface DemoMode { + public static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed"; + void dispatchDemoCommand(String command, Bundle args); public static final String ACTION_DEMO = "com.android.systemui.demo"; diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 0daa5c9..9265b63 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -18,6 +18,7 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; +import android.service.voice.VoiceInteractionSession; import android.util.Log; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -218,7 +219,8 @@ public class AssistManager { } private void startVoiceInteractor(Bundle args) { - mAssistUtils.showSessionForActiveService(args, mShowCallback); + mAssistUtils.showSessionForActiveService(args, + VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, null); } public void launchVoiceAssistFromKeyguard() { @@ -302,4 +304,8 @@ public class AssistManager { public void onUserSwitched(int newUserId) { updateAssistInfo(); } + + public void onLockscreenShown() { + mAssistUtils.onLockscreenShown(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 98558b4..9f21dbe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -25,9 +25,9 @@ import android.os.IBinder; import android.os.Process; import android.util.Log; +import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.policy.IKeyguardStateCallback; import com.android.systemui.SystemUIApplication; @@ -120,9 +120,15 @@ public class KeyguardService extends Service { } @Override // Binder interface - public void onStartedWakingUp(IKeyguardShowCallback callback) { + public void onStartedWakingUp() { checkPermission(); - mKeyguardViewMediator.onStartedWakingUp(callback); + mKeyguardViewMediator.onStartedWakingUp(); + } + + @Override // Binder interface + public void onScreenTurningOn(IKeyguardDrawnCallback callback) { + checkPermission(); + mKeyguardViewMediator.onScreenTurningOn(callback); } @Override // Binder interface diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 009a0d6..7d72dab 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -41,6 +41,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -55,8 +56,9 @@ import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; import android.view.animation.Animation; import android.view.animation.AnimationUtils; + +import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.policy.IKeyguardExitCallback; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.policy.IKeyguardStateCallback; import com.android.internal.telephony.IccCardConstants; import com.android.internal.widget.LockPatternUtils; @@ -77,7 +79,6 @@ import java.util.List; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; - /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -138,7 +139,7 @@ public class KeyguardViewMediator extends SystemUI { private static final int RESET = 4; private static final int VERIFY_UNLOCK = 5; private static final int NOTIFY_SCREEN_OFF = 6; - private static final int NOTIFY_SCREEN_ON = 7; + private static final int NOTIFY_SCREEN_TURNING_ON = 7; private static final int KEYGUARD_DONE = 9; private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; @@ -148,6 +149,7 @@ public class KeyguardViewMediator extends SystemUI { 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; + private static final int NOTIFY_STARTED_WAKING_UP = 21; /** * The default amount of time we stay awake (used for all key input) @@ -311,11 +313,14 @@ public class KeyguardViewMediator extends SystemUI { private boolean mPendingReset; /** - * When starting goign to sleep, we figured out that we need to lock Keyguard and this should be + * When starting going to sleep, we figured out that we need to lock Keyguard and this should be * committed when finished going to sleep. */ private boolean mPendingLock; + private boolean mWakeAndUnlocking; + private IKeyguardDrawnCallback mDrawnCallback; + KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @Override @@ -454,12 +459,24 @@ public class KeyguardViewMediator extends SystemUI { } @Override - public void onFingerprintAuthenticated(int userId) { + public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { + boolean unlockingWithFingerprintAllowed = + mUpdateMonitor.isUnlockingWithFingerprintAllowed(); if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(); + if (unlockingWithFingerprintAllowed) { + mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(); + } } else { - mStatusBarKeyguardViewManager.animateCollapsePanels( - FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); + if (wakeAndUnlocking && unlockingWithFingerprintAllowed) { + mWakeAndUnlocking = true; + keyguardDone(true, true); + } else { + if (wakeAndUnlocking) { + mStatusBarKeyguardViewManager.notifyScreenWakeUpRequested(); + } + mStatusBarKeyguardViewManager.animateCollapsePanels( + FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); + } } }; @@ -752,21 +769,23 @@ public class KeyguardViewMediator extends SystemUI { /** * Let's us know when the device is waking up. */ - public void onStartedWakingUp(IKeyguardShowCallback callback) { + public void onStartedWakingUp() { // TODO: Rename all screen off/on references to interactive/sleeping synchronized (this) { mDeviceInteractive = true; cancelDoKeyguardLaterLocked(); if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence); - if (callback != null) { - notifyScreenOnLocked(callback); - } + notifyStartedWakingUp(); } KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurnedOn(); maybeSendUserPresentBroadcast(); } + public void onScreenTurningOn(IKeyguardDrawnCallback callback) { + notifyScreenOnLocked(callback); + } + private void maybeSendUserPresentBroadcast() { if (mSystemReady && mLockPatternUtils.isLockScreenDisabled( KeyguardUpdateMonitor.getCurrentUser())) { @@ -1093,14 +1112,14 @@ public class KeyguardViewMediator extends SystemUI { mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF); } - /** - * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOn - * @see #handleNotifyScreenOn - */ - private void notifyScreenOnLocked(IKeyguardShowCallback result) { + private void notifyStartedWakingUp() { + if (DEBUG) Log.d(TAG, "notifyStartedWakingUp"); + mHandler.sendEmptyMessage(NOTIFY_STARTED_WAKING_UP); + } + + private void notifyScreenOnLocked(IKeyguardDrawnCallback callback) { if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); - Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, result); + Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNING_ON, callback); mHandler.sendMessage(msg); } @@ -1190,8 +1209,11 @@ public class KeyguardViewMediator extends SystemUI { case NOTIFY_SCREEN_OFF: handleNotifyScreenOff(); break; - case NOTIFY_SCREEN_ON: - handleNotifyScreenOn((IKeyguardShowCallback) msg.obj); + case NOTIFY_SCREEN_TURNING_ON: + handleNotifyScreenTurningOn((IKeyguardDrawnCallback) msg.obj); + break; + case NOTIFY_STARTED_WAKING_UP: + handleNotifyStartedWakingUp(); break; case KEYGUARD_DONE: handleKeyguardDone(msg.arg1 != 0, msg.arg2 != 0); @@ -1354,6 +1376,7 @@ public class KeyguardViewMediator extends SystemUI { setShowingLocked(true); mStatusBarKeyguardViewManager.show(options); mHiding = false; + mWakeAndUnlocking = false; resetKeyguardDonePendingLocked(); mHideAnimationRun = false; updateActivityLockScreenState(); @@ -1375,7 +1398,8 @@ public class KeyguardViewMediator extends SystemUI { // manager until it tells us it's safe to do so with // startKeyguardExitAnimation. ActivityManagerNative.getDefault().keyguardGoingAway( - mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock(), + mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock() + || mWakeAndUnlocking, mStatusBarKeyguardViewManager.isGoingToNotificationShade()); } catch (RemoteException e) { Log.e(TAG, "Error while calling WindowManager", e); @@ -1437,6 +1461,9 @@ public class KeyguardViewMediator extends SystemUI { updateActivityLockScreenState(); adjustStatusBarLocked(); sendUserPresentBroadcast(); + if (mWakeAndUnlocking && mDrawnCallback != null) { + notifyDrawn(mDrawnCallback); + } } } @@ -1508,14 +1535,31 @@ public class KeyguardViewMediator extends SystemUI { } } - /** - * Handle message sent by {@link #notifyScreenOnLocked} - * @see #NOTIFY_SCREEN_ON - */ - private void handleNotifyScreenOn(IKeyguardShowCallback callback) { + private void handleNotifyStartedWakingUp() { synchronized (KeyguardViewMediator.this) { - if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); - mStatusBarKeyguardViewManager.onScreenTurnedOn(callback); + if (DEBUG) Log.d(TAG, "handleNotifyWakingUp"); + mStatusBarKeyguardViewManager.onScreenTurnedOn(); + } + } + + private void handleNotifyScreenTurningOn(IKeyguardDrawnCallback callback) { + synchronized (KeyguardViewMediator.this) { + if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn"); + if (callback != null) { + if (mWakeAndUnlocking) { + mDrawnCallback = callback; + } else { + notifyDrawn(callback); + } + } + } + } + + private void notifyDrawn(final IKeyguardDrawnCallback callback) { + try { + callback.onDrawn(); + } catch (RemoteException e) { + Slog.w(TAG, "Exception calling onDrawn():", e); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java index e9a256c..fe876d7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java @@ -171,6 +171,13 @@ public class RingtonePlayer extends SystemUI { } mAsyncPlayer.stop(); } + + @Override + public String getTitle(Uri uri) { + final UserHandle user = Binder.getCallingUserHandle(); + return Ringtone.getTitle(getContextForUser(user), uri, + false /*followSettingsUri*/, false /*allowRemote*/); + } }; private Context getContextForUser(UserHandle user) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 07406b9..f3ad9d8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -45,6 +45,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> { private final MobileDataController mDataController; private final CellularDetailAdapter mDetailAdapter; + private final CellSignalCallback mSignalCallback = new CellSignalCallback(); + public CellularTile(Host host) { super(host); mController = host.getNetworkController(); @@ -90,8 +92,10 @@ public class CellularTile extends QSTile<QSTile.SignalState> { protected void handleUpdateState(SignalState state, Object arg) { state.visible = mController.hasMobileDataFeature(); if (!state.visible) return; - final CallbackInfo cb = (CallbackInfo) arg; - if (cb == null) return; + CallbackInfo cb = (CallbackInfo) arg; + if (cb == null) { + cb = mSignalCallback.mInfo; + } final Resources r = mContext.getResources(); final int iconId = cb.noSim ? R.drawable.ic_qs_no_sim @@ -152,7 +156,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> { boolean isDataTypeIconWide; } - private final SignalCallback mSignalCallback = new SignalCallbackAdapter() { + private final class CellSignalCallback extends SignalCallbackAdapter { private final CallbackInfo mInfo = new CallbackInfo(); @Override public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index ddde106..7b83e6a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -23,10 +23,9 @@ import android.content.Intent; import com.android.internal.logging.MetricsLogger; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.qs.UsageTracker; import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.UsageTracker; import com.android.systemui.statusbar.policy.HotspotController; -import com.android.systemui.statusbar.policy.KeyguardMonitor; /** Quick settings tile: Hotspot **/ public class HotspotTile extends QSTile<QSTile.BooleanState> { @@ -37,14 +36,12 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { private final HotspotController mController; private final Callback mCallback = new Callback(); private final UsageTracker mUsageTracker; - private final KeyguardMonitor mKeyguard; public HotspotTile(Host host) { super(host); mController = host.getHotspotController(); mUsageTracker = newUsageTracker(host.getContext()); mUsageTracker.setListening(true); - mKeyguard = host.getKeyguardMonitor(); } @Override @@ -97,7 +94,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { if (arg instanceof Boolean) { state.value = (boolean) arg; } else { - mController.isHotspotEnabled(); + state.value = mController.isHotspotEnabled(); } state.icon = state.visible && state.value ? mEnable : mDisable; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java index f7f7acb..3d0dc7b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java @@ -45,6 +45,8 @@ public class IntentTile extends QSTile<QSTile.State> { private int mCurrentUserId; private String mIntentPackage; + private Intent mLastIntent; + private IntentTile(Host host, String action) { super(host); mContext.registerReceiver(mReceiver, new IntentFilter(action)); @@ -112,8 +114,16 @@ public class IntentTile extends QSTile<QSTile.State> { @Override protected void handleUpdateState(State state, Object arg) { - if (!(arg instanceof Intent)) return; - final Intent intent = (Intent) arg; + Intent intent = (Intent) arg; + if (intent == null) { + if (mLastIntent == null) { + return; + } + // No intent but need to refresh state, just use the last one. + intent = mLastIntent; + } + // Save the last one in case we need it later. + mLastIntent = intent; state.visible = intent.getBooleanExtra("visible", true); state.contentDescription = intent.getStringExtra("contentDescription"); state.label = intent.getStringExtra("label"); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 3bfff2f..e654efd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -35,7 +35,6 @@ import com.android.systemui.qs.SignalTileView; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; import com.android.systemui.statusbar.policy.NetworkController.IconState; -import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.SignalCallbackAdapter; import java.util.List; @@ -49,6 +48,8 @@ public class WifiTile extends QSTile<QSTile.SignalState> { private final WifiDetailAdapter mDetailAdapter; private final QSTile.SignalState mStateBeforeClick = newTileState(); + private final WifiSignalCallback mSignalCallback = new WifiSignalCallback(); + public WifiTile(Host host) { super(host); mController = host.getNetworkController(); @@ -118,8 +119,10 @@ public class WifiTile extends QSTile<QSTile.SignalState> { protected void handleUpdateState(SignalState state, Object arg) { state.visible = true; if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg); - if (arg == null) return; CallbackInfo cb = (CallbackInfo) arg; + if (cb == null) { + cb = mSignalCallback.mInfo; + } boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null); boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null); @@ -213,20 +216,21 @@ public class WifiTile extends QSTile<QSTile.SignalState> { } } - private final SignalCallback mSignalCallback = new SignalCallbackAdapter() { + private final class WifiSignalCallback extends SignalCallbackAdapter { + final CallbackInfo mInfo = new CallbackInfo(); + @Override public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, boolean activityIn, boolean activityOut, String description) { if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled); - final CallbackInfo info = new CallbackInfo(); - info.enabled = enabled; - info.connected = qsIcon.visible; - info.wifiSignalIconId = qsIcon.icon; - info.enabledDesc = description; - info.activityIn = activityIn; - info.activityOut = activityOut; - info.wifiSignalContentDescription = qsIcon.contentDescription; - refreshState(info); + mInfo.enabled = enabled; + mInfo.connected = qsIcon.visible; + mInfo.wifiSignalIconId = qsIcon.icon; + mInfo.enabledDesc = description; + mInfo.activityIn = activityIn; + mInfo.activityOut = activityOut; + mInfo.wifiSignalContentDescription = qsIcon.contentDescription; + refreshState(mInfo); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index 7cde44c..403af70 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -656,12 +656,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void setContentAlpha(float contentAlpha) { - int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE - : LAYER_TYPE_HARDWARE; View contentView = getContentView(); - int currentLayerType = contentView.getLayerType(); - if (currentLayerType != layerType) { - contentView.setLayerType(layerType, null); + if (contentView.hasOverlappingRendering()) { + int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE + : LAYER_TYPE_HARDWARE; + int currentLayerType = contentView.getLayerType(); + if (currentLayerType != layerType) { + contentView.setLayerType(layerType, null); + } } contentView.setAlpha(contentAlpha); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index f62dc59..a2e6632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -729,11 +729,15 @@ public abstract class BaseStatusBar extends SystemUI implements } protected void setNotificationShown(StatusBarNotification n) { - mNotificationListener.setNotificationsShown(new String[] { n.getKey() }); + setNotificationsShown(new String[]{n.getKey()}); } protected void setNotificationsShown(String[] keys) { - mNotificationListener.setNotificationsShown(keys); + try { + mNotificationListener.setNotificationsShown(keys); + } catch (RuntimeException e) { + Log.d(TAG, "failed setNotificationsShown: ", e); + } } protected boolean isCurrentProfile(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 58fb2b1..164c496 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -69,7 +69,7 @@ public class KeyguardAffordanceView extends ImageView { private float mCircleStartValue; private boolean mCircleWillBeHidden; private int[] mTempPoint = new int[2]; - private float mImageScale; + private float mImageScale = 1f; private int mCircleColor; private boolean mIsLeft; private View mPreviewView; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 6670ae0..10019f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -86,9 +86,9 @@ public class KeyguardAffordanceHelper { mContext = context; mCallback = callback; initIcons(); - updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false); - updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false); - updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false); + updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true); + updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false, true); + updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true); initDimens(); } @@ -387,15 +387,15 @@ public class KeyguardAffordanceHelper { boolean slowAnimation = isReset && isBelowFalsingThreshold(); if (!isReset) { updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(), - false, false); + false, false, false); } else { updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(), - animateIcons, slowAnimation); + animateIcons, slowAnimation, false); } updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(), - animateIcons, slowAnimation); + animateIcons, slowAnimation, false); updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(), - animateIcons, slowAnimation); + animateIcons, slowAnimation, false); mTranslation = translation; } @@ -431,13 +431,13 @@ public class KeyguardAffordanceHelper { public void animateHideLeftRightIcon() { cancelAnimation(); - updateIcon(mRightIcon, 0f, 0f, true, false); - updateIcon(mLeftIcon, 0f, 0f, true, false); + updateIcon(mRightIcon, 0f, 0f, true, false, false); + updateIcon(mLeftIcon, 0f, 0f, true, false, false); } private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha, - boolean animate, boolean slowRadiusAnimation) { - if (view.getVisibility() != View.VISIBLE) { + boolean animate, boolean slowRadiusAnimation, boolean force) { + if (view.getVisibility() != View.VISIBLE && !force) { return; } view.setCircleRadius(circleRadius, slowRadiusAnimation); 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 91adc46..7c08efc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -106,6 +106,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private PhoneStatusBar mPhoneStatusBar; private final Interpolator mLinearOutSlowInInterpolator; + private boolean mUserSetupComplete; private boolean mPrewarmBound; private Messenger mPrewarmMessenger; private final ServiceConnection mPrewarmConnection = new ServiceConnection() { @@ -250,6 +251,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateCameraVisibility(); // in case onFinishInflate() was called too early } + public void setUserSetupComplete(boolean userSetupComplete) { + mUserSetupComplete = userSetupComplete; + updateCameraVisibility(); + updateLeftAffordanceIcon(); + } + private Intent getCameraIntent() { KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer( @@ -267,7 +274,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser()); boolean visible = !isCameraDisabledByDpm() && resolved != null - && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance); + && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance) + && mUserSetupComplete; mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE); } @@ -275,16 +283,16 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLeftIsVoiceAssist = canLaunchVoiceAssist(); int drawableId; int contentDescription; + boolean visible = mUserSetupComplete; if (mLeftIsVoiceAssist) { - mLeftAffordanceView.setVisibility(View.VISIBLE); drawableId = R.drawable.ic_mic_26dp; contentDescription = R.string.accessibility_voice_assist_button; } else { - boolean visible = isPhoneVisible(); - mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE); + visible &= isPhoneVisible(); drawableId = R.drawable.ic_phone_24dp; contentDescription = R.string.accessibility_phone_button; } + mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE); mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId)); mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription)); } @@ -641,7 +649,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } @Override - public void onFingerprintAuthenticated(int userId) { + public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { } @Override @@ -651,6 +659,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onFingerprintHelp(int msgId, String helpString) { + if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed()) { + return; + } mLockIcon.setTransientFpError(true); mIndicationController.showTransientIndication(helpString, getResources().getColor(R.color.system_warning_color, null)); @@ -660,6 +671,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onFingerprintError(int msgId, String errString) { + if (!KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed()) { + return; + } // TODO: Go to bouncer if this is "too many attempts" (lockout) error. mIndicationController.showTransientIndication(errString, getResources().getColor(R.color.system_warning_color, null)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index a7afec4..e9b2c61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -29,6 +29,7 @@ import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardSecurityView; import com.android.keyguard.R; import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.DejankUtils; import static com.android.keyguard.KeyguardHostView.OnDismissAction; import static com.android.keyguard.KeyguardSecurityModel.SecurityMode; @@ -46,7 +47,6 @@ public class KeyguardBouncer { private KeyguardHostView mKeyguardView; private ViewGroup mRoot; private boolean mShowingSoon; - private Choreographer mChoreographer = Choreographer.getInstance(); private int mBouncerPromptReason; public KeyguardBouncer(Context context, ViewMediatorCallback callback, @@ -70,16 +70,13 @@ public class KeyguardBouncer { return; } - mBouncerPromptReason = mCallback.getBouncerPromptReason(); - // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole // Keyguard. If we need to authenticate, show the bouncer. if (!mKeyguardView.dismiss()) { mShowingSoon = true; // Split up the work over multiple frames. - mChoreographer.postCallbackDelayed(Choreographer.CALLBACK_ANIMATION, mShowRunnable, - null, 16); + DejankUtils.postAfterTraversal(mShowRunnable); } } @@ -107,7 +104,7 @@ public class KeyguardBouncer { } private void cancelShowRunnable() { - mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null); + DejankUtils.removeCallbacks(mShowRunnable); mShowingSoon = false; } @@ -165,6 +162,7 @@ public class KeyguardBouncer { if (wasInitialized) { mKeyguardView.showPrimarySecurityScreen(); } + mBouncerPromptReason = mCallback.getBouncerPromptReason(); } private void ensureView() { 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 9e2ce15..d93f7c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -224,13 +224,14 @@ public class LockIcon extends KeyguardAffordanceView { } private int getState() { - boolean fingerprintRunning = - KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning(); + KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); + boolean fingerprintRunning = updateMonitor.isFingerprintDetectionRunning(); + boolean unlockingAllowed = updateMonitor.isUnlockingWithFingerprintAllowed(); if (mUnlockMethodCache.canSkipBouncer()) { return STATE_LOCK_OPEN; } else if (mTransientFpError) { return STATE_FINGERPRINT_ERROR; - } else if (fingerprintRunning) { + } else if (fingerprintRunning && unlockingAllowed) { return STATE_FINGERPRINT; } else if (mUnlockMethodCache.isFaceUnlockRunning()) { return STATE_FACE_UNLOCK; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index f40f501..416fb36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -40,6 +40,7 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; @@ -184,6 +185,15 @@ public class NavigationBarView extends LinearLayout { mBarTransitions = new NavigationBarTransitions(this); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + ViewRootImpl root = getViewRootImpl(); + if (root != null) { + root.setDrawDuringWindowsAnimating(true); + } + } + public BarTransitions getBarTransitions() { return mBarTransitions; } 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 10191ed..03bdf97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -965,6 +965,7 @@ public class NotificationPanelView extends PanelView implements private void onQsExpansionStarted(int overscrollAmount) { cancelQsAnimation(); cancelHeightAnimator(); + notifyExpandingFinished(); // Reset scroll position and apply that position to the expanded height. float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 889160d..0d20d52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -111,7 +111,7 @@ public abstract class PanelView extends FrameLayout { */ private float mNextCollapseSpeedUpFactor = 1.0f; - private boolean mExpanding; + protected boolean mExpanding; private boolean mGestureWaitForTouchSlop; private boolean mIgnoreXTouchSlop; private Runnable mPeekRunnable = new Runnable() { @@ -137,7 +137,7 @@ public abstract class PanelView extends FrameLayout { } } - private void notifyExpandingFinished() { + protected final void notifyExpandingFinished() { if (mExpanding) { mExpanding = false; onExpandingFinished(); 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 f0927a8..fb940d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -198,6 +198,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; + public static final String ACTION_FAKE_ARTWORK = "fake_artwork"; + private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; private static final int MSG_CLOSE_PANELS = 1001; private static final int MSG_OPEN_SETTINGS_PANEL = 1002; @@ -364,6 +366,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mUserSetup = userSetup; if (!mUserSetup && mStatusBarView != null) animateCollapseQuickSettings(); + if (mKeyguardBottomArea != null) { + mKeyguardBottomArea.setUserSetupComplete(mUserSetup); + } } if (mIconPolicy != null) { mIconPolicy.setCurrentUserSetup(mUserSetup); @@ -434,6 +439,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void onPlaybackStateChanged(PlaybackState state) { super.onPlaybackStateChanged(state); if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state); + if (state != null) { + if (!isPlaybackActive(state.getState())) { + clearCurrentMediaNotification(); + updateMediaMetaData(true); + } + } } @Override @@ -591,7 +602,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, addNavigationBar(); // Lastly, call to the icon policy to install/update all the icons. - mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController); + mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController, + mUserInfoController); mIconPolicy.setCurrentUserSetup(mUserSetup); mSettingsObserver.onChange(false); // set up @@ -834,12 +846,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mFlashlightController = new FlashlightController(mContext); mKeyguardBottomArea.setFlashlightController(mFlashlightController); mKeyguardBottomArea.setPhoneStatusBar(this); + mKeyguardBottomArea.setUserSetupComplete(mUserSetup); mAccessibilityController = new AccessibilityController(mContext); mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); mNextAlarmController = new NextAlarmController(mContext); mKeyguardMonitor = new KeyguardMonitor(mContext); if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { - mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor); + mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, + mHandler); } mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), @@ -890,11 +904,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); + context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + + IntentFilter demoFilter = new IntentFilter(); if (DEBUG_MEDIA_FAKE_ARTWORK) { - filter.addAction("fake_artwork"); + demoFilter.addAction(ACTION_FAKE_ARTWORK); } - filter.addAction(ACTION_DEMO); - context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + demoFilter.addAction(ACTION_DEMO); + context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter, + android.Manifest.permission.DUMP, null); // listen for USER_SETUP_COMPLETE setting (per-user) resetUserSetupObserver(); @@ -1193,6 +1211,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mHeadsUpManager.isHeadsUp(key)) { deferRemoval = !mHeadsUpManager.removeNotification(key); } + if (key.equals(mMediaNotificationKey)) { + clearCurrentMediaNotification(); + updateMediaMetaData(true); + } if (deferRemoval) { mLatestRankingMap = ranking; mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); @@ -1486,23 +1508,31 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, synchronized (mNotificationData) { ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); final int N = activeNotifications.size(); + + // Promote the media notification with a controller in 'playing' state, if any. Entry mediaNotification = null; MediaController controller = null; for (int i = 0; i < N; i++) { final Entry entry = activeNotifications.get(i); if (isMediaNotification(entry)) { - final MediaSession.Token token = entry.notification.getNotification().extras + final MediaSession.Token token = + entry.notification.getNotification().extras .getParcelable(Notification.EXTRA_MEDIA_SESSION); if (token != null) { - controller = new MediaController(mContext, token); - if (controller != null) { - // we've got a live one, here + MediaController aController = new MediaController(mContext, token); + if (PlaybackState.STATE_PLAYING == + getMediaControllerPlaybackState(aController)) { + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching " + + entry.notification.getKey()); + } mediaNotification = entry; + controller = aController; + break; } } } } - if (mediaNotification == null) { // Still nothing? OK, let's just look for live media sessions and see if they match // one of our notifications. This will catch apps that aren't (yet!) using media @@ -1515,83 +1545,88 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, UserHandle.USER_ALL); for (MediaController aController : sessions) { - if (aController == null) continue; - final PlaybackState state = aController.getPlaybackState(); - if (state == null) continue; - switch (state.getState()) { - case PlaybackState.STATE_STOPPED: - case PlaybackState.STATE_ERROR: - continue; - default: - // now to see if we have one like this - final String pkg = aController.getPackageName(); - - for (int i = 0; i < N; i++) { - final Entry entry = activeNotifications.get(i); - if (entry.notification.getPackageName().equals(pkg)) { - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: found controller matching " - + entry.notification.getKey()); - } - controller = aController; - mediaNotification = entry; - break; + if (PlaybackState.STATE_PLAYING == + getMediaControllerPlaybackState(aController)) { + // now to see if we have one like this + final String pkg = aController.getPackageName(); + + for (int i = 0; i < N; i++) { + final Entry entry = activeNotifications.get(i); + if (entry.notification.getPackageName().equals(pkg)) { + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: found controller matching " + + entry.notification.getKey()); } + controller = aController; + mediaNotification = entry; + break; } + } } } } } - if (!sameSessions(mMediaController, controller)) { + if (controller != null && !sameSessions(mMediaController, controller)) { // We have a new media session - - if (mMediaController != null) { - // something old was playing - Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " - + mMediaController); - mMediaController.unregisterCallback(mMediaListener); - } + clearCurrentMediaNotification(); mMediaController = controller; + mMediaController.registerCallback(mMediaListener); + mMediaMetadata = mMediaController.getMetadata(); + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " + + mMediaMetadata); + } - if (mMediaController != null) { - mMediaController.registerCallback(mMediaListener); - mMediaMetadata = mMediaController.getMetadata(); + if (mediaNotification != null) { + mMediaNotificationKey = mediaNotification.notification.getKey(); if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " - + mMediaMetadata); + Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" + + mMediaNotificationKey + " controller=" + mMediaController); } - - final String notificationKey = mediaNotification == null - ? null - : mediaNotification.notification.getKey(); - - if (notificationKey == null || !notificationKey.equals(mMediaNotificationKey)) { - // we have a new notification! - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key=" - + notificationKey + " controller=" + controller); - } - mMediaNotificationKey = notificationKey; - } - } else { - mMediaMetadata = null; - mMediaNotificationKey = null; } - metaDataChanged = true; - } else { - // Media session unchanged - - if (DEBUG_MEDIA) { - Log.v(TAG, "DEBUG_MEDIA: Continuing media notification: key=" + mMediaNotificationKey); - } } } + if (metaDataChanged) { + updateNotifications(); + } updateMediaMetaData(metaDataChanged); } + private int getMediaControllerPlaybackState(MediaController controller) { + if (controller != null) { + final PlaybackState playbackState = controller.getPlaybackState(); + if (playbackState != null) { + return playbackState.getState(); + } + } + return PlaybackState.STATE_NONE; + } + + private boolean isPlaybackActive(int state) { + if (state != PlaybackState.STATE_STOPPED + && state != PlaybackState.STATE_ERROR + && state != PlaybackState.STATE_NONE) { + return true; + } + return false; + } + + private void clearCurrentMediaNotification() { + mMediaNotificationKey = null; + mMediaMetadata = null; + if (mMediaController != null) { + if (DEBUG_MEDIA) { + Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: " + + mMediaController.getPackageName()); + } + mMediaController.unregisterCallback(mMediaListener); + } + mMediaController = null; + } + private boolean sameSessions(MediaController a, MediaController b) { if (a == b) return true; if (a == null) return false; @@ -1657,7 +1692,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } if (metaDataChanged) { if (mBackdropBack.getDrawable() != null) { - Drawable drawable = mBackdropBack.getDrawable(); + Drawable drawable = + mBackdropBack.getDrawable().getConstantState().newDrawable().mutate(); mBackdropFront.setImageDrawable(drawable); if (mScrimSrcModeEnabled) { mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); @@ -1730,7 +1766,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private int adjustDisableFlags(int state) { - if (!mLaunchTransitionFadingAway + if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) { state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS; state |= StatusBarManager.DISABLE_SYSTEM_INFO; @@ -2677,6 +2713,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mBluetoothController != null) { mBluetoothController.dump(fd, pw, args); } + if (mHotspotController != null) { + mHotspotController.dump(fd, pw, args); + } if (mCastController != null) { mCastController.dump(fd, pw, args); } @@ -2849,7 +2888,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mScreenOn = true; notifyNavigationBarScreenOn(true); } - else if (ACTION_DEMO.equals(action)) { + } + }; + + private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (DEBUG) Log.v(TAG, "onReceive: " + intent); + String action = intent.getAction(); + if (ACTION_DEMO.equals(action)) { Bundle bundle = intent.getExtras(); if (bundle != null) { String command = bundle.getString("command", "").trim().toLowerCase(); @@ -2861,7 +2907,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } } - } else if ("fake_artwork".equals(action)) { + } else if (ACTION_FAKE_ARTWORK.equals(action)) { if (DEBUG_MEDIA_FAKE_ARTWORK) { updateMediaMetaData(true); } @@ -2910,7 +2956,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, updateRowStates(); mIconController.updateResources(); mScreenPinningRequest.onConfigurationChanged(); - mNetworkController.handleConfigurationChanged(); + mNetworkController.onConfigurationChanged(); } @Override @@ -3185,6 +3231,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHandlerThread = null; } mContext.unregisterReceiver(mBroadcastReceiver); + mContext.unregisterReceiver(mDemoReceiver); mAssistManager.destroy(); final SignalClusterView signalCluster = @@ -3208,7 +3255,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void dispatchDemoCommand(String command, Bundle args) { if (!mDemoModeAllowed) { mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), - "sysui_demo_allowed", 0) != 0; + DEMO_MODE_ALLOWED, 0) != 0; } if (!mDemoModeAllowed) return; if (command.equals(COMMAND_ENTER)) { @@ -3308,6 +3355,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mDraggedDownRow.notifyHeightChanged(false /* needsAnimation */); mDraggedDownRow = null; } + mAssistManager.onLockscreenShown(); } private void onLaunchTransitionFadingEnded() { @@ -3457,7 +3505,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, startTime + fadeoutDuration - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION, StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION); - disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */); + disable(mDisabledUnmodified1, mDisabledUnmodified2, fadeoutDuration > 0 /* animate */); } public boolean isKeyguardFadingAway() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index b2a67bd..53dae5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -44,6 +44,7 @@ import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.HotspotController; +import com.android.systemui.statusbar.policy.UserInfoController; /** * This class contains all of the policy about which icons are installed in the status @@ -69,6 +70,7 @@ public class PhoneStatusBarPolicy { private final CastController mCast; private final HotspotController mHotspot; private final AlarmManager mAlarmManager; + private final UserInfoController mUserInfoController; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. @@ -111,12 +113,14 @@ public class PhoneStatusBarPolicy { } }; - public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) { + public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot, + UserInfoController userInfoController) { mContext = context; mCast = cast; mHotspot = hotspot; mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + mUserInfoController = userInfoController; // listen for broadcasts IntentFilter filter = new IntentFilter(); @@ -360,6 +364,7 @@ public class PhoneStatusBarPolicy { new IUserSwitchObserver.Stub() { @Override public void onUserSwitching(int newUserId, IRemoteCallback reply) { + mUserInfoController.reloadUserInfo(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 6d04b28..c0887ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -24,6 +24,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import com.android.systemui.DejankUtils; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -117,12 +118,12 @@ public class PhoneStatusBarView extends PanelBar { public void onAllPanelsCollapsed() { super.onAllPanelsCollapsed(); // Close the status bar in the next frame so we can show the end of the animation. - postOnAnimation(mHideExpandedRunnable); + DejankUtils.postAfterTraversal(mHideExpandedRunnable); mLastFullyOpenedPanel = null; } public void removePendingHideExpandedRunnables() { - removeCallbacks(mHideExpandedRunnable); + DejankUtils.removeCallbacks(mHideExpandedRunnable); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java new file mode 100644 index 0000000..a1e9ece --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java @@ -0,0 +1,174 @@ +/* + * 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 com.android.systemui.statusbar.phone; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +import com.android.keyguard.AlphaOptimizedImageButton; + +public class SettingsButton extends AlphaOptimizedImageButton { + + private static final long LONG_PRESS_LENGTH = 1000; + private static final long ACCEL_LENGTH = 750; + private static final long FULL_SPEED_LENGTH = 375; + private static final long RUN_DURATION = 350; + + private boolean mUpToSpeed; + private ObjectAnimator mAnimator; + + private float mSlop; + + public SettingsButton(Context context, AttributeSet attrs) { + super(context, attrs); + mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + public boolean isAnimating() { + return mAnimator != null && mAnimator.isRunning(); + } + + public boolean isTunerClick() { + return mUpToSpeed; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + postDelayed(mLongPressCallback, LONG_PRESS_LENGTH); + break; + case MotionEvent.ACTION_UP: + if (mUpToSpeed) { + startExitAnimation(); + } else { + cancelLongClick(); + } + break; + case MotionEvent.ACTION_CANCEL: + cancelLongClick(); + break; + case MotionEvent.ACTION_MOVE: + float x = event.getX(); + float y = event.getY(); + if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop) + || (y > getHeight() + mSlop)) { + cancelLongClick(); + } + break; + } + return super.onTouchEvent(event); + } + + private void cancelLongClick() { + cancelAnimation(); + mUpToSpeed = false; + removeCallbacks(mLongPressCallback); + } + + private void cancelAnimation() { + if (mAnimator != null) { + mAnimator.removeAllListeners(); + mAnimator.cancel(); + mAnimator = null; + } + } + + private void startExitAnimation() { + animate() + .translationX(((View) getParent().getParent()).getWidth() - getX()) + .alpha(0) + .setDuration(RUN_DURATION) + .setInterpolator(AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.accelerate_cubic)) + .setListener(new AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + setAlpha(1f); + setTranslationX(0); + cancelLongClick(); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + }) + .start(); + } + + protected void startAccelSpin() { + cancelAnimation(); + mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360); + mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.accelerate_quad)); + mAnimator.setDuration(ACCEL_LENGTH); + mAnimator.addListener(new AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + startContinuousSpin(); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + }); + mAnimator.start(); + } + + protected void startContinuousSpin() { + cancelAnimation(); + mUpToSpeed = true; + mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360); + mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext, + android.R.interpolator.linear)); + mAnimator.setDuration(FULL_SPEED_LENGTH); + mAnimator.setRepeatCount(Animation.INFINITE); + mAnimator.start(); + } + + private final Runnable mLongPressCallback = new Runnable() { + @Override + public void run() { + startAccelSpin(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index a81f06e..5d58cd0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -37,6 +37,7 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.Switch; import android.widget.TextView; +import android.widget.Toast; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.BatteryMeterView; @@ -48,6 +49,7 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.tuner.TunerService; import java.text.NumberFormat; @@ -73,7 +75,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private TextView mDateExpanded; private LinearLayout mSystemIcons; private View mSignalCluster; - private View mSettingsButton; + private SettingsButton mSettingsButton; + private View mSettingsContainer; private View mQsDetailHeader; private TextView mQsDetailHeaderTitle; private Switch mQsDetailHeaderSwitch; @@ -142,7 +145,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar); mDateCollapsed = (TextView) findViewById(R.id.date_collapsed); mDateExpanded = (TextView) findViewById(R.id.date_expanded); - mSettingsButton = findViewById(R.id.settings_button); + mSettingsButton = (SettingsButton) findViewById(R.id.settings_button); + mSettingsContainer = findViewById(R.id.settings_button_container); mSettingsButton.setOnClickListener(this); mQsDetailHeader = findViewById(R.id.qs_detail_header); mQsDetailHeader.setAlpha(0); @@ -323,13 +327,15 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE); mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); - mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); + mSettingsContainer.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE); if (mSignalCluster != null) { updateSignalClusterDetachment(); } mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE); + mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility( + TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE); } private void updateSignalClusterDetachment() { @@ -352,7 +358,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private void updateSystemIconsLayoutParams() { RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams(); int rule = mExpanded - ? mSettingsButton.getId() + ? mSettingsContainer.getId() : mMultiUserSwitch.getId(); if (rule != lp.getRules()[RelativeLayout.START_OF]) { lp.addRule(RelativeLayout.START_OF, rule); @@ -495,6 +501,20 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL @Override public void onClick(View v) { if (v == mSettingsButton) { + if (mSettingsButton.isTunerClick()) { + if (TunerService.isTunerEnabled(mContext)) { + TunerService.showResetRequest(mContext, new Runnable() { + @Override + public void run() { + // Relaunch settings so that the tuner disappears. + startSettingsActivity(); + } + }); + } else { + Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show(); + TunerService.setTunerEnabled(mContext, true); + } + } startSettingsActivity(); } else if (v == mSystemIconsSuperContainer) { startBatteryActivity(); @@ -567,10 +587,10 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL } target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop(); target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel); - target.settingsAlpha = getAlphaForVisibility(mSettingsButton); + target.settingsAlpha = getAlphaForVisibility(mSettingsContainer); target.settingsTranslation = mExpanded ? 0 - : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft(); + : mMultiUserSwitch.getLeft() - mSettingsContainer.getLeft(); target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f; target.settingsRotation = !mExpanded ? 90f : 0f; } @@ -622,9 +642,11 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSignalCluster.setTranslationX(0f); mSignalCluster.setTranslationY(0f); } - mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); - mSettingsButton.setTranslationX(values.settingsTranslation); - mSettingsButton.setRotation(values.settingsRotation); + if (!mSettingsButton.isAnimating()) { + mSettingsContainer.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); + mSettingsContainer.setTranslationX(values.settingsTranslation); + mSettingsButton.setRotation(values.settingsRotation); + } applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha); if (!mShowingDetail && !mDetailTransitioning) { // Otherwise it needs to stay invisible @@ -633,7 +655,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL applyAlpha(mDateCollapsed, values.dateCollapsedAlpha); applyAlpha(mDateExpanded, values.dateExpandedAlpha); applyAlpha(mBatteryLevel, values.batteryLevelAlpha); - applyAlpha(mSettingsButton, values.settingsAlpha); + applyAlpha(mSettingsContainer, values.settingsAlpha); applyAlpha(mSignalCluster, values.signalClusterAlpha); if (!mExpanded) { mTime.setScaleX(1f); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index a69416a..6b3a59d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -19,15 +19,12 @@ package com.android.systemui.statusbar.phone; import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Bundle; -import android.os.RemoteException; import android.os.SystemClock; -import android.util.Slog; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManagerGlobal; -import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; @@ -153,6 +150,7 @@ public class StatusBarKeyguardViewManager { } else { showBouncerOrKeyguard(); } + KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset(); updateStates(); } } @@ -163,26 +161,10 @@ public class StatusBarKeyguardViewManager { mBouncer.onScreenTurnedOff(); } - public void onScreenTurnedOn(final IKeyguardShowCallback callback) { + public void onScreenTurnedOn() { mScreenOn = true; mScreenWillWakeUp = false; mPhoneStatusBar.onScreenTurnedOn(); - if (callback != null) { - callbackAfterDraw(callback); - } - } - - private void callbackAfterDraw(final IKeyguardShowCallback callback) { - mContainer.post(new Runnable() { - @Override - public void run() { - try { - callback.onShown(mContainer.getWindowToken()); - } catch (RemoteException e) { - Slog.w(TAG, "Exception calling onShown():", e); - } - } - }); } public void notifyScreenWakeUpRequested() { @@ -270,16 +252,22 @@ public class StatusBarKeyguardViewManager { mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration); boolean staying = mPhoneStatusBar.hideKeyguard(); if (!staying) { - mStatusBarWindowManager.setKeyguardFadingAway(true); - mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { - @Override - public void run() { - mStatusBarWindowManager.setKeyguardFadingAway(false); - mPhoneStatusBar.finishKeyguardFadingAway(); - WindowManagerGlobal.getInstance().trimMemory( - ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); - } - }); + if (fadeoutDuration == 0) { + mPhoneStatusBar.finishKeyguardFadingAway(); + WindowManagerGlobal.getInstance().trimMemory( + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + } else { + mStatusBarWindowManager.setKeyguardFadingAway(true); + mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { + @Override + public void run() { + mStatusBarWindowManager.setKeyguardFadingAway(false); + mPhoneStatusBar.finishKeyguardFadingAway(); + WindowManagerGlobal.getInstance().trimMemory( + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + } + }); + } } else { mScrimController.animateGoingToFullShade(delay, fadeoutDuration); mPhoneStatusBar.finishKeyguardFadingAway(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java index 6fc15a8..c8c45e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java @@ -132,7 +132,10 @@ public class UnlockMethodCache { } @Override - public void onFingerprintAuthenticated(int userId) { + public void onFingerprintAuthenticated(int userId, boolean wakeAndUnlocking) { + if (!mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()) { + return; + } update(false /* updateAlways */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 1e3bc4d..41aeac9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.policy; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -27,6 +26,8 @@ import android.util.Log; import com.android.settingslib.TetherUtil; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; public class HotspotControllerImpl implements HotspotController { @@ -43,11 +44,32 @@ public class HotspotControllerImpl implements HotspotController { private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final Receiver mReceiver = new Receiver(); private final Context mContext; - private final WifiManager mWifiManager; + + private int mHotspotState; public HotspotControllerImpl(Context context) { mContext = context; - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("HotspotController state:"); + pw.print(" mHotspotEnabled="); pw.println(stateToString(mHotspotState)); + } + + private static String stateToString(int hotspotState) { + switch (hotspotState) { + case WifiManager.WIFI_AP_STATE_DISABLED: + return "DISABLED"; + case WifiManager.WIFI_AP_STATE_DISABLING: + return "DISABLING"; + case WifiManager.WIFI_AP_STATE_ENABLED: + return "ENABLED"; + case WifiManager.WIFI_AP_STATE_ENABLING: + return "ENABLING"; + case WifiManager.WIFI_AP_STATE_FAILED: + return "FAILED"; + } + return null; } public void addCallback(Callback callback) { @@ -66,7 +88,7 @@ public class HotspotControllerImpl implements HotspotController { @Override public boolean isHotspotEnabled() { - return mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED; + return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED; } @Override @@ -76,7 +98,6 @@ public class HotspotControllerImpl implements HotspotController { @Override public void setHotspotEnabled(boolean enabled) { - final ContentResolver cr = mContext.getContentResolver(); // Call provisioning app which is called when enabling Tethering from Settings if (enabled && TetherUtil.isProvisioningNeeded(mContext)) { mContext.startServiceAsUser(TETHER_SERVICE_INTENT, UserHandle.CURRENT); @@ -113,7 +134,8 @@ public class HotspotControllerImpl implements HotspotController { if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction()); int state = intent.getIntExtra( WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); - fireCallback(WifiManager.WIFI_AP_STATE_ENABLED == state); + mHotspotState = state; + fireCallback(mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 81f2d53..57dfff5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -31,6 +31,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.provider.Settings; +import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -117,6 +118,9 @@ public class NetworkControllerImpl extends BroadcastReceiver // Handler that all callbacks are made on. private final CallbackHandler mCallbackHandler; + @VisibleForTesting + ServiceState mLastServiceState; + /** * Construct this controller object and register for updates. */ @@ -194,10 +198,10 @@ public class NetworkControllerImpl extends BroadcastReceiver filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); + filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); mContext.registerReceiver(this, filter, null, mReceiverHandler); mListening = true; @@ -260,6 +264,11 @@ public class NetworkControllerImpl extends BroadcastReceiver } public boolean isEmergencyOnly() { + if (mMobileSignalControllers.size() == 0) { + // When there are no active subscriptions, determine emengency state from last + // broadcast. + return mLastServiceState != null && mLastServiceState.isEmergencyOnly(); + } int voiceSubId = mSubDefaults.getDefaultVoiceSubId(); if (!SubscriptionManager.isValidSubscriptionId(voiceSubId)) { for (MobileSignalController mobileSignalController : @@ -339,8 +348,6 @@ public class NetworkControllerImpl extends BroadcastReceiver if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { updateConnectivity(); - } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { - handleConfigurationChanged(); } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { refreshLocale(); updateAirplaneMode(false); @@ -356,6 +363,13 @@ public class NetworkControllerImpl extends BroadcastReceiver } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { // Might have different subscriptions now. updateMobileControllers(); + } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) { + mLastServiceState = ServiceState.newFromBundle(intent.getExtras()); + if (mMobileSignalControllers.size() == 0) { + // If none of the subscriptions are active, we might need to recalculate + // emergency state. + recalculateEmergency(); + } } else { int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -373,8 +387,18 @@ public class NetworkControllerImpl extends BroadcastReceiver } } - public void handleConfigurationChanged() { + public void onConfigurationChanged() { mConfig = Config.readConfig(mContext); + mReceiverHandler.post(new Runnable() { + @Override + public void run() { + handleConfigurationChanged(); + } + }); + } + + @VisibleForTesting + void handleConfigurationChanged() { for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { mobileSignalController.setConfiguration(mConfig); } @@ -580,6 +604,8 @@ public class NetworkControllerImpl extends BroadcastReceiver pw.println(mAirplaneMode); pw.print(" mLocale="); pw.println(mLocale); + pw.print(" mLastServiceState="); + pw.println(mLastServiceState); for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) { mobileSignalController.dump(pw); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 6fabe9b..3e8d4e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -39,6 +39,8 @@ import android.os.UserManager; import android.provider.Settings; import android.util.Log; import android.util.SparseArray; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; @@ -68,6 +70,11 @@ public class UserSwitcherController { private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING = "lockscreenSimpleUserSwitcher"; private static final String ACTION_REMOVE_GUEST = "com.android.systemui.REMOVE_GUEST"; + private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000; + + private static final int ID_REMOVE_GUEST = 1010; + private static final String TAG_REMOVE_GUEST = "remove_guest"; + private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; private final Context mContext; private final UserManager mUserManager; @@ -75,6 +82,7 @@ public class UserSwitcherController { private final GuestResumeSessionReceiver mGuestResumeSessionReceiver = new GuestResumeSessionReceiver(); private final KeyguardMonitor mKeyguardMonitor; + private final Handler mHandler; private ArrayList<UserRecord> mUsers = new ArrayList<>(); private Dialog mExitGuestDialog; @@ -82,11 +90,15 @@ public class UserSwitcherController { private int mLastNonGuestUser = UserHandle.USER_OWNER; private boolean mSimpleUserSwitcher; private boolean mAddUsersWhenLocked; + private boolean mPauseRefreshUsers; + private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); - public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor) { + public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor, + Handler handler) { mContext = context; mGuestResumeSessionReceiver.register(context); mKeyguardMonitor = keyguardMonitor; + mHandler = handler; mUserManager = UserManager.get(context); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_ADDED); @@ -94,10 +106,13 @@ public class UserSwitcherController { filter.addAction(Intent.ACTION_USER_INFO_CHANGED); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_STOPPING); - filter.addAction(ACTION_REMOVE_GUEST); mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, null /* permission */, null /* scheduler */); + filter = new IntentFilter(); + filter.addAction(ACTION_REMOVE_GUEST); + mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter, + PERMISSION_SELF, null /* scheduler */); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(SIMPLE_USER_SWITCHER_GLOBAL_SETTING), true, @@ -122,17 +137,26 @@ public class UserSwitcherController { */ @SuppressWarnings("unchecked") private void refreshUsers(int forcePictureLoadForId) { + if (DEBUG) Log.d(TAG, "refreshUsers(forcePictureLoadForId=" + forcePictureLoadForId+")"); + if (forcePictureLoadForId != UserHandle.USER_NULL) { + mForcePictureLoadForUserId.put(forcePictureLoadForId, true); + } + + if (mPauseRefreshUsers) { + return; + } SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size()); final int N = mUsers.size(); for (int i = 0; i < N; i++) { UserRecord r = mUsers.get(i); - if (r == null || r.info == null - || r.info.id == forcePictureLoadForId || r.picture == null) { + if (r == null || r.picture == null || + r.info == null || mForcePictureLoadForUserId.get(r.info.id)) { continue; } bitmaps.put(r.info.id, r.picture); } + mForcePictureLoadForUserId.clear(); final boolean addUsersWhenLocked = mAddUsersWhenLocked; new AsyncTask<SparseArray<Bitmap>, Void, ArrayList<UserRecord>>() { @@ -215,6 +239,13 @@ public class UserSwitcherController { }.execute((SparseArray) bitmaps); } + private void pauseRefreshUsers() { + if (!mPauseRefreshUsers) { + mHandler.postDelayed(mUnpauseRefreshUsers, PAUSE_REFRESH_USERS_TIMEOUT_MS); + mPauseRefreshUsers = true; + } + } + private void notifyAdapters() { for (int i = mAdapters.size() - 1; i >= 0; i--) { BaseUserAdapter adapter = mAdapters.get(i).get(); @@ -261,6 +292,7 @@ public class UserSwitcherController { private void switchToUserId(int id) { try { + pauseRefreshUsers(); ActivityManagerNative.getDefault().switchUser(id); } catch (RemoteException e) { Log.e(TAG, "Couldn't switch user.", e); @@ -302,6 +334,10 @@ public class UserSwitcherController { Log.v(TAG, "Broadcast: a=" + intent.getAction() + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); } + + boolean unpauseRefreshUsers = false; + int forcePictureLoadForId = UserHandle.USER_NULL; + if (ACTION_REMOVE_GUEST.equals(intent.getAction())) { int currentUser = ActivityManager.getCurrentUser(); UserInfo userInfo = mUserManager.getUserInfo(currentUser); @@ -309,16 +345,13 @@ public class UserSwitcherController { showExitGuestDialog(currentUser); } return; - } - if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { + } else if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) { final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); UserInfo userInfo = mUserManager.getUserInfo(currentId); if (userInfo != null && userInfo.isGuest()) { showGuestNotification(currentId); } - } - - if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { + } else if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { mExitGuestDialog.cancel(); mExitGuestDialog = null; @@ -343,13 +376,15 @@ public class UserSwitcherController { } } notifyAdapters(); - } - int forcePictureLoadForId = UserHandle.USER_NULL; - if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) { + unpauseRefreshUsers = true; + } else if (Intent.ACTION_USER_INFO_CHANGED.equals(intent.getAction())) { forcePictureLoadForId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); } refreshUsers(forcePictureLoadForId); + if (unpauseRefreshUsers) { + mUnpauseRefreshUsers.run(); + } } private void showGuestNotification(int guestUserId) { @@ -366,8 +401,17 @@ public class UserSwitcherController { mContext.getString(R.string.guest_notification_remove_action), removeGuestPI) .build(); - NotificationManager.from(mContext).notifyAsUser(null, 0, notification, - new UserHandle(guestUserId)); + NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST, + notification, new UserHandle(guestUserId)); + } + }; + + private final Runnable mUnpauseRefreshUsers = new Runnable() { + @Override + public void run() { + mHandler.removeCallbacks(this); + mPauseRefreshUsers = false; + refreshUsers(UserHandle.USER_NULL); } }; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java index 3f5ca58..a2b062c 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java @@ -28,13 +28,14 @@ import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.preference.SwitchPreference; import android.provider.Settings; +import android.view.MenuItem; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.DemoMode; import com.android.systemui.R; public class DemoModeFragment extends PreferenceFragment implements OnPreferenceChangeListener { - private static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed"; private static final String DEMO_MODE_ON = "sysui_tuner_demo_on"; private static final String[] STATUS_ICONS = { @@ -75,10 +76,33 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference updateDemoModeEnabled(); updateDemoModeOn(); ContentResolver contentResolver = getContext().getContentResolver(); - contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ALLOWED), false, - mDemoModeObserver); + contentResolver.registerContentObserver(Settings.Global.getUriFor( + DemoMode.DEMO_MODE_ALLOWED), false, mDemoModeObserver); contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ON), false, mDemoModeObserver); + setHasOptionsMenu(true); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + getFragmentManager().popBackStack(); + break; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onResume() { + super.onResume(); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, true); + } + + @Override + public void onPause() { + super.onPause(); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, false); } @Override @@ -89,7 +113,7 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference private void updateDemoModeEnabled() { boolean enabled = Settings.Global.getInt(getContext().getContentResolver(), - DEMO_MODE_ALLOWED, 0) != 0; + DemoMode.DEMO_MODE_ALLOWED, 0) != 0; mEnabledSwitch.setChecked(enabled); mOnSwitch.setEnabled(enabled); } @@ -102,15 +126,18 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference @Override public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean enabled = newValue == Boolean.TRUE; if (preference == mEnabledSwitch) { - if (newValue != Boolean.TRUE) { + if (!enabled) { // Make sure we aren't in demo mode when disabling it. mOnSwitch.setChecked(false); stopDemoMode(); } - setGlobal(DEMO_MODE_ALLOWED, newValue == Boolean.TRUE ? 1 : 0); + MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ENABLED, enabled); + setGlobal(DemoMode.DEMO_MODE_ALLOWED, enabled ? 1 : 0); } else if (preference == mOnSwitch) { - if (newValue == Boolean.TRUE) { + MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ON, enabled); + if (enabled) { startDemoMode(); } else { stopDemoMode(); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java index a5b244e..37ac098 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java @@ -40,6 +40,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ScrollView; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; @@ -79,12 +80,25 @@ public class QsTuner extends Fragment implements Callback { menu.add(0, MENU_RESET, 0, com.android.internal.R.string.reset); } + public void onResume() { + super.onResume(); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_QS, true); + } + + public void onPause() { + super.onPause(); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_QS, false); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_RESET: mTileHost.reset(); break; + case android.R.id.home: + getFragmentManager().popBackStack(); + break; } return super.onOptionsItemSelected(item); } @@ -205,6 +219,8 @@ public class QsTuner extends Fragment implements Callback { if (oldTile.equals(newTile)) { return; } + MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REORDER, oldTile + "," + + newTile); List<String> order = new ArrayList<>(mTileSpecs); int index = order.indexOf(oldTile); if (index < 0) { @@ -217,12 +233,14 @@ public class QsTuner extends Fragment implements Callback { } public void remove(String tile) { + MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REMOVE, tile); List<String> tiles = new ArrayList<>(mTileSpecs); tiles.remove(tile); setTiles(tiles); } public void add(String tile) { + MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_ADD, tile); List<String> tiles = new ArrayList<>(mTileSpecs); tiles.add(tile); setTiles(tiles); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java index d4cc56d..e5b550e 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java @@ -23,6 +23,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService.Tunable; @@ -50,11 +51,14 @@ public class StatusBarSwitch extends SwitchPreference implements Tunable { if (!value) { // If not enabled add to blacklist. if (!mBlacklist.contains(getKey())) { + MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_DISABLE, + getKey()); mBlacklist.add(getKey()); setList(mBlacklist); } } else { if (mBlacklist.remove(getKey())) { + MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_ENABLE, getKey()); setList(mBlacklist); } } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 4a8c2e4..71b5de5 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -17,7 +17,10 @@ package com.android.systemui.tuner; import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING; +import android.app.AlertDialog; import android.app.FragmentTransaction; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.database.ContentObserver; import android.net.Uri; import android.os.Bundle; @@ -28,19 +31,29 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.SwitchPreference; +import android.provider.Settings; import android.provider.Settings.System; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.tuner.TunerService.Tunable; public class TunerFragment extends PreferenceFragment { + private static final String TAG = "TunerFragment"; + private static final String KEY_QS_TUNER = "qs_tuner"; private static final String KEY_DEMO_MODE = "demo_mode"; private static final String KEY_BATTERY_PCT = "battery_pct"; + public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning"; + + private static final int MENU_REMOVE = Menu.FIRST + 1; + private final SettingObserver mSettingObserver = new SettingObserver(); private SwitchPreference mBatteryPct; @@ -73,6 +86,19 @@ public class TunerFragment extends PreferenceFragment { } }); mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT); + if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING, + 0) == 0) { + new AlertDialog.Builder(getContext()) + .setTitle(R.string.tuner_warning_title) + .setMessage(R.string.tuner_warning) + .setPositiveButton(R.string.got_it, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Settings.Secure.putInt(getContext().getContentResolver(), + SETTING_SEEN_TUNER_WARNING, 1); + } + }).show(); + } } @Override @@ -83,6 +109,7 @@ public class TunerFragment extends PreferenceFragment { System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); registerPrefs(getPreferenceScreen()); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true); } @Override @@ -91,6 +118,7 @@ public class TunerFragment extends PreferenceFragment { getContext().getContentResolver().unregisterContentObserver(mSettingObserver); unregisterPrefs(getPreferenceScreen()); + MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, false); } private void registerPrefs(PreferenceGroup group) { @@ -120,11 +148,24 @@ public class TunerFragment extends PreferenceFragment { } @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.add(Menu.NONE, MENU_REMOVE, Menu.NONE, R.string.remove_from_settings); + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: getActivity().finish(); return true; + case MENU_REMOVE: + TunerService.showResetRequest(getContext(), new Runnable() { + @Override + public void run() { + getActivity().finish(); + } + }); + return true; } return super.onOptionsItemSelected(item); } @@ -152,6 +193,7 @@ public class TunerFragment extends PreferenceFragment { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean v = (Boolean) newValue; + MetricsLogger.action(getContext(), MetricsLogger.TUNER_BATTERY_PERCENTAGE, v); System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index de5aaf6..d3f33ab 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -16,8 +16,15 @@ package com.android.systemui.tuner; import android.app.ActivityManager; +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; @@ -25,9 +32,13 @@ import android.os.Looper; import android.provider.Settings; import android.util.ArrayMap; +import com.android.systemui.BatteryMeterView; +import com.android.systemui.DemoMode; +import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.SystemUIApplication; import com.android.systemui.settings.CurrentUserTracker; +import com.android.systemui.statusbar.phone.SystemUIDialog; import java.util.ArrayList; import java.util.HashMap; @@ -36,6 +47,8 @@ import java.util.List; public class TunerService extends SystemUI { + public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER"; + private final Observer mObserver = new Observer(); // Map of Uris we listen on to their settings keys. private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); @@ -118,6 +131,19 @@ public class TunerService extends SystemUI { } } + public void clearAll() { + // A couple special cases. + Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); + Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null); + Intent intent = new Intent(DemoMode.ACTION_DEMO); + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); + mContext.sendBroadcast(intent); + + for (String key : mTunableLookup.keySet()) { + Settings.Secure.putString(mContentResolver, key, null); + } + } + // Only used in other processes, such as the tuner. private static TunerService sInstance; @@ -141,6 +167,44 @@ public class TunerService extends SystemUI { return sInstance; } + public static final void showResetRequest(final Context context, final Runnable onDisabled) { + SystemUIDialog dialog = new SystemUIDialog(context); + dialog.setMessage(R.string.remove_from_settings_prompt); + dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel), + (OnClickListener) null); + dialog.setButton(DialogInterface.BUTTON_POSITIVE, + context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Tell the tuner (in main SysUI process) to clear all its settings. + context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR)); + // Disable access to tuner. + TunerService.setTunerEnabled(context, false); + // Make them sit through the warning dialog again. + Settings.Secure.putInt(context.getContentResolver(), + TunerFragment.SETTING_SEEN_TUNER_WARNING, 0); + if (onDisabled != null) { + onDisabled.run(); + } + } + }); + dialog.show(); + } + + public static final void setTunerEnabled(Context context, boolean enabled) { + context.getPackageManager().setComponentEnabledSetting( + new ComponentName(context, TunerActivity.class), + enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED + : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + } + + public static final boolean isTunerEnabled(Context context) { + return context.getPackageManager().getComponentEnabledSetting( + new ComponentName(context, TunerActivity.class)) + == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + } + private class Observer extends ContentObserver { public Observer() { super(new Handler(Looper.getMainLooper())); @@ -157,4 +221,13 @@ public class TunerService extends SystemUI { public interface Tunable { void onTuningChanged(String key, String newValue); } + + public static class ClearReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_CLEAR.equals(intent.getAction())) { + get(context).clearAll(); + } + } + } } |
