diff options
Diffstat (limited to 'packages/SystemUI/src')
37 files changed, 1207 insertions, 981 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 0d331d1..3fbc76b 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -225,23 +225,23 @@ public class BatteryMeterView extends View implements DemoMode, mSubpixelSmoothingRight = context.getResources().getFraction( R.fraction.battery_subpixel_smoothing_right, 1, 1); - mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mFramePaint = new Paint(); mFramePaint.setColor(frameColor); mFramePaint.setDither(true); mFramePaint.setStrokeWidth(0); mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE); - mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBatteryPaint = new Paint(); mBatteryPaint.setDither(true); mBatteryPaint.setStrokeWidth(0); mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE); - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint = new Paint(); Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); mTextPaint.setTypeface(font); mTextPaint.setTextAlign(Paint.Align.CENTER); - mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mWarningTextPaint = new Paint(); mWarningTextPaint.setColor(mColors[1]); font = Typeface.create("sans-serif", Typeface.BOLD); mWarningTextPaint.setTypeface(font); @@ -249,7 +249,7 @@ public class BatteryMeterView extends View implements DemoMode, mChargeColor = context.getColor(R.color.batterymeter_charge_color); - mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBoltPaint = new Paint(); mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color)); mBoltPoints = loadBoltPoints(res); diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 68b1968..29d2a01 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -37,8 +37,10 @@ public final class Prefs { Key.DND_TILE_VISIBLE, Key.DND_TILE_COMBINED_ICON, Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, + Key.DND_CONFIRMED_SILENCE_INTRODUCTION, Key.DND_FAVORITE_BUCKET_INDEX, Key.DND_NONE_SELECTED, + Key.DND_FAVORITE_ZEN, }) public @interface Key { String SEARCH_APP_WIDGET_ID = "searchAppWidgetId"; @@ -48,8 +50,10 @@ public final class Prefs { String DND_TILE_VISIBLE = "DndTileVisible"; String DND_TILE_COMBINED_ICON = "DndTileCombinedIcon"; String DND_CONFIRMED_PRIORITY_INTRODUCTION = "DndConfirmedPriorityIntroduction"; + String DND_CONFIRMED_SILENCE_INTRODUCTION = "DndConfirmedSilenceIntroduction"; String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex"; String DND_NONE_SELECTED = "DndNoneSelected"; + String DND_FAVORITE_ZEN = "DndFavoriteZen"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 7b555fc..6479dc5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -539,10 +539,11 @@ public class KeyguardViewMediator extends SystemUI { mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); mLockPatternUtils = new LockPatternUtils(mContext); - mLockPatternUtils.setCurrentUser(ActivityManager.getCurrentUser()); + KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser()); // Assume keyguard is showing (unless it's disabled) until we know for sure... - setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled()); + setShowingLocked(!shouldWaitForProvisioning() && !mLockPatternUtils.isLockScreenDisabled( + KeyguardUpdateMonitor.getCurrentUser())); mTrustManager.reportKeyguardShowingChanged(); mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(mContext, @@ -623,8 +624,10 @@ public class KeyguardViewMediator extends SystemUI { // Lock immediately based on setting if secure (user has a pin/pattern/password). // This also "locks" the device when not secure to provide easy access to the // camera while preventing unwanted input. + int currentUser = KeyguardUpdateMonitor.getCurrentUser(); final boolean lockImmediately = - mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure(); + mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser) + || !mLockPatternUtils.isSecure(currentUser); notifyScreenOffLocked(); @@ -670,7 +673,7 @@ public class KeyguardViewMediator extends SystemUI { // From DevicePolicyAdmin final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() - .getMaximumTimeToLock(null, mLockPatternUtils.getCurrentUser()); + .getMaximumTimeToLock(null, KeyguardUpdateMonitor.getCurrentUser()); long timeout; if (policyTimeout > 0) { @@ -719,7 +722,8 @@ public class KeyguardViewMediator extends SystemUI { } private void maybeSendUserPresentBroadcast() { - if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()) { + if (mSystemReady && mLockPatternUtils.isLockScreenDisabled( + KeyguardUpdateMonitor.getCurrentUser())) { // Lock screen is disabled because the user has set the preference to "None". // In this case, send out ACTION_USER_PRESENT here instead of in // handleKeyguardDone() @@ -733,7 +737,7 @@ public class KeyguardViewMediator extends SystemUI { */ public void onDreamingStarted() { synchronized (this) { - if (mScreenOn && mLockPatternUtils.isSecure()) { + if (mScreenOn && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) { doKeyguardLaterLocked(); } } @@ -974,12 +978,13 @@ public class KeyguardViewMediator extends SystemUI { return; } - if (mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) { + if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser()) + && !lockedOrMissing) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); return; } - if (mLockPatternUtils.checkVoldPassword()) { + if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) { if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted"); // Without this, settings is not enabled until the lock screen first appears setShowingLocked(false); @@ -1072,7 +1077,7 @@ public class KeyguardViewMediator extends SystemUI { } public boolean isSecure() { - return mLockPatternUtils.isSecure() + return mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()) || KeyguardUpdateMonitor.getInstance(mContext).isSimPinSecure(); } @@ -1083,7 +1088,7 @@ public class KeyguardViewMediator extends SystemUI { * @param newUserId The id of the incoming user. */ public void setCurrentUser(int newUserId) { - mLockPatternUtils.setCurrentUser(newUserId); + KeyguardUpdateMonitor.setCurrentUser(newUserId); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -1213,7 +1218,7 @@ public class KeyguardViewMediator extends SystemUI { private void sendUserPresentBroadcast() { synchronized (this) { if (mBootCompleted) { - final UserHandle currentUser = new UserHandle(mLockPatternUtils.getCurrentUser()); + final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser()); final UserManager um = (UserManager) mContext.getSystemService( Context.USER_SERVICE); List <UserInfo> userHandles = um.getProfiles(currentUser.getIdentifier()); @@ -1393,14 +1398,9 @@ public class KeyguardViewMediator extends SystemUI { updateActivityLockScreenState(); adjustStatusBarLocked(); sendUserPresentBroadcast(); - maybeStopListeningForFingerprint(); } } - private void maybeStopListeningForFingerprint() { - mUpdateMonitor.stopListeningForFingerprint(); - } - private void adjustStatusBarLocked() { if (mStatusBarManager == null) { mStatusBarManager = (StatusBarManager) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 6ce63d6..5145bc7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -37,7 +37,11 @@ import com.android.systemui.volume.ZenModePanel; /** Quick settings tile: Do not disturb **/ public class DndTile extends QSTile<QSTile.BooleanState> { - private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); + private static final Intent ZEN_SETTINGS = + new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); + + private static final Intent ZEN_PRIORITY_SETTINGS = + new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS); private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE"; private static final String EXTRA_VISIBLE = "visible"; @@ -87,7 +91,9 @@ public class DndTile extends QSTile<QSTile.BooleanState> { if (mState.value) { mController.setZen(Global.ZEN_MODE_OFF, null, TAG); } else { - mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG); + int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS); + mController.setZen(zen, null, TAG); + refreshState(zen); // this one's optimistic showDetail(true); } } @@ -209,8 +215,8 @@ public class DndTile extends QSTile<QSTile.BooleanState> { R.layout.zen_mode_panel, parent, false); if (convertView == null) { zmp.init(mController); - zmp.setEmbedded(true); zmp.addOnAttachStateChangeListener(this); + zmp.setCallback(mZenModePanelCallback); } return zmp; } @@ -225,4 +231,22 @@ public class DndTile extends QSTile<QSTile.BooleanState> { mShowingDetail = false; } } + + private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() { + @Override + public void onPrioritySettings() { + mHost.startSettingsActivity(ZEN_PRIORITY_SETTINGS); + } + + @Override + public void onInteraction() { + // noop + } + + @Override + public void onExpanded(boolean expanded) { + // noop + } + }; + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 7271469..26c3b4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -87,6 +87,7 @@ import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.statusbar.StatusBarIconList; import com.android.internal.util.NotificationColorUtil; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SwipeHelper; @@ -639,7 +640,7 @@ public abstract class BaseStatusBar extends SystemUI implements Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) { Log.d(TAG, "user hasn't seen notification about hidden notifications"); final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); - if (!lockPatternUtils.isSecure()) { + if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) { Log.d(TAG, "insecure lockscreen, skipping notification"); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); @@ -708,18 +709,6 @@ public abstract class BaseStatusBar extends SystemUI implements mNotificationListener.setNotificationsShown(keys); } - protected void setNotificationsShownAll() { - ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications(); - final int N = activeNotifications.size(); - - String[] keys = new String[N]; - for (int i = 0; i < N; i++) { - NotificationData.Entry entry = activeNotifications.get(i); - keys[i] = entry.key; - } - setNotificationsShown(keys); - } - protected boolean isCurrentProfile(int userId) { synchronized (mCurrentProfiles) { return userId == UserHandle.USER_ALL || mCurrentProfiles.get(userId) != null; @@ -795,7 +784,8 @@ public abstract class BaseStatusBar extends SystemUI implements protected void applyColorsAndBackgrounds(StatusBarNotification sbn, NotificationData.Entry entry) { - if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) { + if (entry.getContentView().getId() + != com.android.internal.R.id.status_bar_latest_event_content) { // Using custom RemoteViews if (entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) { @@ -820,8 +810,9 @@ public abstract class BaseStatusBar extends SystemUI implements public boolean isMediaNotification(NotificationData.Entry entry) { // TODO: confirm that there's a valid media key - return entry.expandedBig != null && - entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null; + return entry.getExpandedContentView() != null && + entry.getExpandedContentView() + .findViewById(com.android.internal.R.id.media_actions) != null; } // The gear button in the guts that links to the app's own notification settings @@ -1145,9 +1136,9 @@ public abstract class BaseStatusBar extends SystemUI implements } /** - * if the interrupting notification had a fullscreen intent, fire it now. + * If there is an active heads-up notification and it has a fullscreen intent, fire it now. */ - public abstract void escalateHeadsUp(); + public abstract void maybeEscalateHeadsUp(); /** * Save the current "public" (locked and secure) state of the lockscreen. @@ -1348,8 +1339,8 @@ public abstract class BaseStatusBar extends SystemUI implements View publicViewLocal = null; if (publicNotification != null) { try { - publicViewLocal = publicNotification.contentView.apply(mContext, contentContainerPublic, - mOnClickHandler); + publicViewLocal = publicNotification.contentView.apply(mContext, + contentContainerPublic, mOnClickHandler); if (publicViewLocal != null) { publicViewLocal.setIsRootNamespace(true); @@ -1456,9 +1447,7 @@ public abstract class BaseStatusBar extends SystemUI implements entry.row = row; entry.row.setHeightRange(mRowMinHeight, maxHeight); entry.row.setOnActivatedListener(this); - entry.expanded = contentViewLocal; - entry.expandedPublic = publicViewLocal; - entry.setBigContentView(bigContentViewLocal); + entry.row.setExpandable(bigContentViewLocal != null); applyColorsAndBackgrounds(sbn, entry); @@ -1547,12 +1536,13 @@ public abstract class BaseStatusBar extends SystemUI implements // See if we have somewhere to put that remote input if (remoteInput != null) { - if (entry.expandedBig != null) { - inflateRemoteInput(entry.expandedBig, remoteInput, actions); + View bigContentView = entry.getExpandedContentView(); + if (bigContentView != null) { + inflateRemoteInput(bigContentView, remoteInput, actions); } - View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild(); - if (headsUpChild != null) { - inflateRemoteInput(headsUpChild, remoteInput, actions); + View headsUpContentView = entry.getHeadsUpContentView(); + if (headsUpContentView != null) { + inflateRemoteInput(headsUpContentView, remoteInput, actions); } } @@ -1701,7 +1691,6 @@ public abstract class BaseStatusBar extends SystemUI implements boolean clearNotificationEffects = (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED); mBarService.onPanelRevealed(clearNotificationEffects); - setNotificationsShownAll(); } else { mBarService.onPanelHidden(); } @@ -1895,15 +1884,14 @@ public abstract class BaseStatusBar extends SystemUI implements logUpdate(entry, n); } boolean applyInPlace = shouldApplyInPlace(entry, n); - final boolean shouldInterrupt = shouldInterrupt(notification); - final boolean alertAgain = alertAgain(entry, n); + boolean shouldInterrupt = shouldInterrupt(notification); + boolean alertAgain = alertAgain(entry, n); entry.notification = notification; mGroupManager.onEntryUpdated(entry, entry.notification); boolean updateSuccessful = false; if (applyInPlace) { - // We can just reapply the notifications in place if (DEBUG) Log.d(TAG, "reusing notification for key: " + key); try { if (entry.icon != null) { @@ -1924,7 +1912,7 @@ public abstract class BaseStatusBar extends SystemUI implements updateSuccessful = true; } catch (RuntimeException e) { - // It failed to add cleanly. Log, and remove the view from the panel. + // It failed to apply cleanly. Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e); } } @@ -1948,11 +1936,12 @@ public abstract class BaseStatusBar extends SystemUI implements // swipe-dismissable) updateNotificationVetoButton(entry.row, notification); - // Is this for you? - boolean isForCurrentUser = isNotificationForCurrentProfiles(notification); - if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you"); + if (DEBUG) { + // Is this for you? + boolean isForCurrentUser = isNotificationForCurrentProfiles(notification); + Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you"); + } - // Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); } @@ -1963,7 +1952,7 @@ public abstract class BaseStatusBar extends SystemUI implements StatusBarNotification oldNotification = oldEntry.notification; Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when + " ongoing=" + oldNotification.isOngoing() - + " expanded=" + oldEntry.expanded + + " expanded=" + oldEntry.getContentView() + " contentView=" + oldNotification.getNotification().contentView + " bigContentView=" + oldNotification.getNotification().bigContentView + " publicView=" + oldNotification.getNotification().publicVersion @@ -1976,7 +1965,8 @@ public abstract class BaseStatusBar extends SystemUI implements } /** - * @return whether we can just reapply the RemoteViews in place when it is updated + * @return whether we can just reapply the RemoteViews from a notification in-place when it is + * updated */ private boolean shouldApplyInPlace(Entry entry, Notification n) { StatusBarNotification oldNotification = entry.notification; @@ -1994,15 +1984,15 @@ public abstract class BaseStatusBar extends SystemUI implements final Notification publicNotification = n.publicVersion; final RemoteViews publicContentView = publicNotification != null ? publicNotification.contentView : null; - boolean contentsUnchanged = entry.expanded != null + boolean contentsUnchanged = entry.getContentView() != null && contentView.getPackage() != null && oldContentView.getPackage() != null && oldContentView.getPackage().equals(contentView.getPackage()) && oldContentView.getLayoutId() == contentView.getLayoutId(); // large view may be null boolean bigContentsUnchanged = - (entry.getBigContentView() == null && bigContentView == null) - || ((entry.getBigContentView() != null && bigContentView != null) + (entry.getExpandedContentView() == null && bigContentView == null) + || ((entry.getExpandedContentView() != null && bigContentView != null) && bigContentView.getPackage() != null && oldBigContentView.getPackage() != null && oldBigContentView.getPackage().equals(bigContentView.getPackage()) @@ -2034,12 +2024,12 @@ public abstract class BaseStatusBar extends SystemUI implements : null; // Reapply the RemoteViews - contentView.reapply(mContext, entry.expanded, mOnClickHandler); - if (bigContentView != null && entry.getBigContentView() != null) { - bigContentView.reapply(mContext, entry.getBigContentView(), + contentView.reapply(mContext, entry.getContentView(), mOnClickHandler); + if (bigContentView != null && entry.getExpandedContentView() != null) { + bigContentView.reapply(mContext, entry.getExpandedContentView(), mOnClickHandler); } - View headsUpChild = entry.row.getPrivateLayout().getHeadsUpChild(); + View headsUpChild = entry.getHeadsUpContentView(); if (headsUpContentView != null && headsUpChild != null) { headsUpContentView.reapply(mContext, headsUpChild, mOnClickHandler); } @@ -2062,7 +2052,7 @@ public abstract class BaseStatusBar extends SystemUI implements } protected void notifyHeadsUpScreenOff() { - escalateHeadsUp(); + maybeEscalateHeadsUp(); } private boolean alertAgain(Entry oldEntry, Notification newNotification) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index cb8217e..9ef495d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -84,7 +84,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { private ExpansionLogger mLogger; private String mLoggingKey; private boolean mWasReset; - private NotificationGuts mGuts; private StatusBarNotification mStatusBarNotification; private boolean mIsHeadsUp; @@ -102,6 +101,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { private ViewStub mGutsStub; private boolean mHasExpandAction; private boolean mIsSystemChildExpanded; + private boolean mIsPinned; private OnClickListener mExpandClickListener = new OnClickListener() { @Override public void onClick(View v) { @@ -109,7 +109,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { !mChildrenExpanded); } }; - private boolean mInShade; public NotificationContentView getPrivateLayout() { return mPrivateLayout; @@ -284,12 +283,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { return realActualHeight; } - public void setInShade(boolean inShade) { - mInShade = inShade; + /** + * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this + * the notification will be rendered on top of the screen. + * + * @param pinned whether it is pinned + */ + public void setPinned(boolean pinned) { + mIsPinned = pinned; } - public boolean isInShade() { - return mInShade; + public boolean isPinned() { + return mIsPinned; } public int getHeadsUpHeight() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 1c53655..110b14c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -32,37 +32,34 @@ import android.widget.FrameLayout; import com.android.systemui.R; /** - * A frame layout containing the actual payload of the notification, including the contracted and - * expanded layout. This class is responsible for clipping the content and and switching between the - * expanded and contracted view depending on its clipped size. + * A frame layout containing the actual payload of the notification, including the contracted, + * expanded and heads up layout. This class is responsible for clipping the content and and + * switching between the expanded, contracted and the heads up view depending on its clipped size. */ public class NotificationContentView extends FrameLayout { private static final long ANIMATION_DURATION_LENGTH = 170; - private static final int CONTRACTED = 1; - private static final int EXPANDED = 2; - private static final int HEADSUP = 3; + private static final int VISIBLE_TYPE_CONTRACTED = 0; + private static final int VISIBLE_TYPE_EXPANDED = 1; + private static final int VISIBLE_TYPE_HEADSUP = 2; private final Rect mClipBounds = new Rect(); + private final int mSmallHeight; + private final int mHeadsUpHeight; + private final Interpolator mLinearInterpolator = new LinearInterpolator(); private View mContractedChild; private View mExpandedChild; private View mHeadsUpChild; private NotificationViewWrapper mContractedWrapper; - - private final int mSmallHeight; - private final int mHeadsUpHeight; private int mClipTopAmount; - private int mContentHeight; - - private final Interpolator mLinearInterpolator = new LinearInterpolator(); - private int mVisibleView = CONTRACTED; - + private int mVisibleType = VISIBLE_TYPE_CONTRACTED; private boolean mDark; private final Paint mFadePaint = new Paint(); private boolean mAnimate; + private boolean mIsHeadsUp; private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -72,7 +69,6 @@ public class NotificationContentView extends FrameLayout { return true; } }; - private boolean mIsHeadsUp; public NotificationContentView(Context context, AttributeSet attrs) { super(context, attrs); @@ -105,9 +101,9 @@ public class NotificationContentView extends FrameLayout { // An actual height is set size = Math.min(maxSize, layoutParams.height); } - int spec = size == Integer.MAX_VALUE ? - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) : - MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); + int spec = size == Integer.MAX_VALUE + ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST); mExpandedChild.measure(widthMeasureSpec, spec); maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight()); } @@ -153,7 +149,7 @@ public class NotificationContentView extends FrameLayout { mContractedChild = null; mExpandedChild = null; mHeadsUpChild = null; - mVisibleView = CONTRACTED; + mVisibleType = VISIBLE_TYPE_CONTRACTED; if (resetActualHeight) { mContentHeight = mSmallHeight; } @@ -263,30 +259,32 @@ public class NotificationContentView extends FrameLayout { if (mContractedChild == null) { return; } - int visibleView = calculateVisibleView(); - if (visibleView != mVisibleView || force) { - if (animate && mExpandedChild != null) { - runSwitchAnimation(visibleView); + int visibleType = calculateVisibleType(); + if (visibleType != mVisibleType || force) { + if (animate && (visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null) + || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null) + || visibleType == VISIBLE_TYPE_CONTRACTED) { + runSwitchAnimation(visibleType); } else { - updateViewVisibilities(visibleView); + updateViewVisibilities(visibleType); } - mVisibleView = visibleView; + mVisibleType = visibleType; } } - private void updateViewVisibilities(int visibleView) { - boolean contractedVisible = visibleView == CONTRACTED; + private void updateViewVisibilities(int visibleType) { + boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED; mContractedChild.setVisibility(contractedVisible ? View.VISIBLE : View.INVISIBLE); mContractedChild.setAlpha(contractedVisible ? 1f : 0f); mContractedChild.setLayerType(LAYER_TYPE_NONE, null); if (mExpandedChild != null) { - boolean expandedVisible = visibleView == EXPANDED; + boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED; mExpandedChild.setVisibility(expandedVisible ? View.VISIBLE : View.INVISIBLE); mExpandedChild.setAlpha(expandedVisible ? 1f : 0f); mExpandedChild.setLayerType(LAYER_TYPE_NONE, null); } if (mHeadsUpChild != null) { - boolean headsUpVisible = visibleView == HEADSUP; + boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP; mHeadsUpChild.setVisibility(headsUpVisible ? View.VISIBLE : View.INVISIBLE); mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f); mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null); @@ -294,9 +292,9 @@ public class NotificationContentView extends FrameLayout { setLayerType(LAYER_TYPE_NONE, null); } - private void runSwitchAnimation(int visibleView) { - View shownView = getViewFromFlag(visibleView); - View hiddenView = getViewFromFlag(mVisibleView); + private void runSwitchAnimation(int visibleType) { + View shownView = getViewForVisibleType(visibleType); + View hiddenView = getViewForVisibleType(mVisibleType); shownView.setVisibility(View.VISIBLE); hiddenView.setVisibility(View.VISIBLE); shownView.setLayerType(LAYER_TYPE_HARDWARE, mFadePaint); @@ -314,34 +312,42 @@ public class NotificationContentView extends FrameLayout { .withEndAction(new Runnable() { @Override public void run() { - updateViewVisibilities(mVisibleView); + updateViewVisibilities(mVisibleType); } }); } - private View getViewFromFlag(int visibleView) { - switch (visibleView) { - case EXPANDED: + /** + * @param visibleType one of the static enum types in this view + * @return the corresponding view according to the given visible type + */ + private View getViewForVisibleType(int visibleType) { + switch (visibleType) { + case VISIBLE_TYPE_EXPANDED: return mExpandedChild; - case HEADSUP: + case VISIBLE_TYPE_HEADSUP: return mHeadsUpChild; + default: + return mContractedChild; } - return mContractedChild; } - private int calculateVisibleView() { + /** + * @return one of the static enum types in this view, calculated form the current state + */ + private int calculateVisibleType() { boolean noExpandedChild = mExpandedChild == null; if (mIsHeadsUp && mHeadsUpChild != null) { if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) { - return HEADSUP; + return VISIBLE_TYPE_HEADSUP; } else { - return EXPANDED; + return VISIBLE_TYPE_EXPANDED; } } else { if (mContentHeight <= mSmallHeight || noExpandedChild) { - return CONTRACTED; + return VISIBLE_TYPE_CONTRACTED; } else { - return EXPANDED; + return VISIBLE_TYPE_EXPANDED; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 429889d..2a8b4ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -45,9 +45,6 @@ public class NotificationData { public StatusBarNotification notification; public StatusBarIconView icon; public ExpandableNotificationRow row; // the outer expanded view - public View expanded; // the inflated RemoteViews - public View expandedPublic; // for insecure lockscreens - public View expandedBig; private boolean interruption; public boolean autoRedacted; // whether the redacted notification was generated by us public boolean legacy; // whether the notification has a legacy, dark background @@ -58,14 +55,6 @@ public class NotificationData { this.notification = n; this.icon = ic; } - public void setBigContentView(View bigContentView) { - this.expandedBig = bigContentView; - row.setExpandable(bigContentView != null); - } - public View getBigContentView() { - return expandedBig; - } - public View getPublicContentView() { return expandedPublic; } public void setInterruption() { interruption = true; @@ -81,15 +70,28 @@ public class NotificationData { public void reset() { // NOTE: Icon needs to be preserved for now. // We should fix this at some point. - expanded = null; - expandedPublic = null; - expandedBig = null; autoRedacted = false; legacy = false; if (row != null) { row.reset(); } } + + public View getContentView() { + return row.getPrivateLayout().getContractedChild(); + } + + public View getExpandedContentView() { + return row.getPrivateLayout().getExpandedChild(); + } + + public View getHeadsUpContentView() { + return row.getPrivateLayout().getHeadsUpChild(); + } + + public View getPublicContentView() { + return row.getPublicLayout().getContractedChild(); + } } private final ArrayMap<String, Entry> mEntries = new ArrayMap<>(); @@ -258,7 +260,7 @@ public class NotificationData { */ public boolean hasActiveClearableNotifications() { for (Entry e : mSortedAndFiltered) { - if (e.expanded != null) { // the view successfully inflated + if (e.getContentView() != null) { // the view successfully inflated if (e.notification.isClearable()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index 3997807..fe7bc97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -27,7 +27,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; /** - * A Helper class to handle touches on the heads-up views + * A helper class to handle touches on the heads-up views. */ public class HeadsUpTouchHelper implements Gefingerpoken { @@ -37,19 +37,30 @@ public class HeadsUpTouchHelper implements Gefingerpoken { private float mTouchSlop; private float mInitialTouchX; private float mInitialTouchY; - private boolean mMotionOnHeadsUpView; + private boolean mTouchingHeadsUpView; private boolean mTrackingHeadsUp; private boolean mCollapseSnoozes; private NotificationPanelView mPanel; private ExpandableNotificationRow mPickedChild; + public HeadsUpTouchHelper(HeadsUpManager headsUpManager, + NotificationStackScrollLayout stackScroller, + NotificationPanelView notificationPanelView) { + mHeadsUpManager = headsUpManager; + mStackScroller = stackScroller; + mPanel = notificationPanelView; + Context context = stackScroller.getContext(); + final ViewConfiguration configuration = ViewConfiguration.get(context); + mTouchSlop = configuration.getScaledTouchSlop(); + } + public boolean isTrackingHeadsUp() { return mTrackingHeadsUp; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (!mMotionOnHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) { + if (!mTouchingHeadsUpView && event.getActionMasked() != MotionEvent.ACTION_DOWN) { return false; } int pointerIndex = event.findPointerIndex(mTrackingPointer); @@ -65,10 +76,10 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchX = x; setTrackingHeadsUp(false); ExpandableView child = mStackScroller.getChildAtPosition(x, y); - mMotionOnHeadsUpView = false; + mTouchingHeadsUpView = false; if (child instanceof ExpandableNotificationRow) { mPickedChild = (ExpandableNotificationRow) child; - mMotionOnHeadsUpView = mPickedChild.isHeadsUp() && !mPickedChild.isInShade(); + mTouchingHeadsUpView = mPickedChild.isHeadsUp() && mPickedChild.isPinned(); } break; case MotionEvent.ACTION_POINTER_UP: @@ -97,7 +108,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - if (mPickedChild != null && mMotionOnHeadsUpView) { + if (mPickedChild != null && mTouchingHeadsUpView) { + // We may swallow this click if the heads up just came in. if (mHeadsUpManager.shouldSwallowClick( mPickedChild.getStatusBarNotification().getKey())) { endMotion(); @@ -141,20 +153,6 @@ public class HeadsUpTouchHelper implements Gefingerpoken { private void endMotion() { mTrackingPointer = -1; mPickedChild = null; - mMotionOnHeadsUpView = false; - } - - public ExpandableView getPickedChild() { - return mPickedChild; - } - - public void bind(HeadsUpManager headsUpManager, NotificationStackScrollLayout stackScroller, - NotificationPanelView notificationPanelView) { - mHeadsUpManager = headsUpManager; - mStackScroller = stackScroller; - mPanel = notificationPanelView; - Context context = stackScroller.getContext(); - final ViewConfiguration configuration = ViewConfiguration.get(context); - mTouchSlop = configuration.getScaledTouchSlop(); + mTouchingHeadsUpView = false; } } 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 e5ef6ff..fabc1a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -86,7 +86,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private KeyguardAffordanceView mCameraImageView; private KeyguardAffordanceView mPhoneImageView; - private KeyguardAffordanceView mLockIcon; + private LockIcon mLockIcon; private TextView mIndicationText; private ViewGroup mPreviewContainer; @@ -102,11 +102,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private AccessibilityController mAccessibilityController; private PhoneStatusBar mPhoneStatusBar; - private final TrustDrawable mTrustDrawable; private final Interpolator mLinearOutSlowInInterpolator; - private int mLastUnlockIconRes = 0; private boolean mPrewarmSent; - private boolean mTransientFpError; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -123,7 +120,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mTrustDrawable = new TrustDrawable(mContext); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); } @@ -169,20 +165,19 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container); mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button); mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button); - mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon); + mLockIcon = (LockIcon) findViewById(R.id.lock_icon); mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text); watchForCameraPolicyChanges(); updateCameraVisibility(); updatePhoneVisibility(); mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); mUnlockMethodCache.addListener(this); - updateLockIcon(); + mLockIcon.update(); setClipChildren(false); setClipToPadding(false); mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); inflatePreviews(); mLockIcon.setOnClickListener(this); - mLockIcon.setBackground(mTrustDrawable); mLockIcon.setOnLongClickListener(this); mCameraImageView.setOnClickListener(this); mPhoneImageView.setOnClickListener(this); @@ -222,6 +217,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void setAccessibilityController(AccessibilityController accessibilityController) { mAccessibilityController = accessibilityController; + mLockIcon.setAccessibilityController(accessibilityController); accessibilityController.addStateChangedCallback(this); } @@ -233,9 +229,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private Intent getCameraIntent() { KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); boolean currentUserHasTrust = updateMonitor.getUserHasTrust( - mLockPatternUtils.getCurrentUser()); - return mLockPatternUtils.isSecure() && !currentUserHasTrust - ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; + KeyguardUpdateMonitor.getCurrentUser()); + boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()); + return (secure && !currentUserHasTrust) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT; } private void updateCameraVisibility() { @@ -245,7 +241,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(), PackageManager.MATCH_DEFAULT_ONLY, - mLockPatternUtils.getCurrentUser()); + KeyguardUpdateMonitor.getCurrentUser()); boolean visible = !isCameraDisabledByDpm() && resolved != null && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance); mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE); @@ -294,21 +290,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mPhoneImageView.setClickable(touchExplorationEnabled); mCameraImageView.setFocusable(accessibilityEnabled); mPhoneImageView.setFocusable(accessibilityEnabled); - updateLockIconClickability(); - } - - private void updateLockIconClickability() { - if (mAccessibilityController == null) { - return; - } - boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled(); - boolean clickToForceLock = mUnlockMethodCache.isTrustManaged() - && !mAccessibilityController.isAccessibilityEnabled(); - boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged() - && !clickToForceLock; - mLockIcon.setClickable(clickToForceLock || clickToUnlock); - mLockIcon.setLongClickable(longClickToForceLock); - mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled()); + mLockIcon.update(); } @Override @@ -339,13 +321,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL 0 /* velocityDp - N/A */); mIndicationController.showTransientIndication( R.string.keyguard_indication_trust_disabled); - mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser()); + mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser()); } public void prewarmCamera() { Intent intent = getCameraIntent(); String targetPackage = PreviewInflater.getTargetPackage(mContext, intent, - mLockPatternUtils.getCurrentUser()); + KeyguardUpdateMonitor.getCurrentUser()); if (targetPackage != null) { Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM); prewarm.setPackage(targetPackage); @@ -361,7 +343,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mPrewarmSent = false; Intent intent = getCameraIntent(); String targetPackage = PreviewInflater.getTargetPackage(mContext, intent, - mLockPatternUtils.getCurrentUser()); + KeyguardUpdateMonitor.getCurrentUser()); if (targetPackage != null) { Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN); prewarm.setPackage(targetPackage); @@ -375,7 +357,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mPrewarmSent = false; final Intent intent = getCameraIntent(); boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity( - mContext, intent, mLockPatternUtils.getCurrentUser()); + mContext, intent, KeyguardUpdateMonitor.getCurrentUser()); if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { AsyncTask.execute(new Runnable() { @Override @@ -409,69 +391,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - if (isShown()) { - mTrustDrawable.start(); - } else { - mTrustDrawable.stop(); - } if (changedView == this && visibility == VISIBLE) { - updateLockIcon(); + mLockIcon.update(); updateCameraVisibility(); } } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mTrustDrawable.stop(); - } - - private void updateLockIcon() { - boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); - if (visible) { - mTrustDrawable.start(); - } else { - mTrustDrawable.stop(); - } - if (!visible) { - return; - } - // TODO: Real icon for facelock. - boolean isFingerprintIcon = - KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning(); - boolean anyFingerprintIcon = isFingerprintIcon || mTransientFpError; - int iconRes = mTransientFpError ? R.drawable.ic_fingerprint_error - : isFingerprintIcon ? R.drawable.ic_fingerprint - : mUnlockMethodCache.isFaceUnlockRunning() - ? com.android.internal.R.drawable.ic_account_circle - : mUnlockMethodCache.isCurrentlyInsecure() ? R.drawable.ic_lock_open_24dp - : R.drawable.ic_lock_24dp; - - if (mLastUnlockIconRes != iconRes) { - Drawable icon = mContext.getDrawable(iconRes); - int iconHeight = getResources().getDimensionPixelSize( - R.dimen.keyguard_affordance_icon_height); - int iconWidth = getResources().getDimensionPixelSize( - R.dimen.keyguard_affordance_icon_width); - if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight - || icon.getIntrinsicWidth() != iconWidth)) { - icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight); - } - mLockIcon.setImageDrawable(icon); - mLockIcon.setPaddingRelative(0, 0, 0, anyFingerprintIcon - ? getResources().getDimensionPixelSize( - R.dimen.fingerprint_icon_additional_padding) - : 0); - mLockIcon.setRestingAlpha( - anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT); - } - - // Hide trust circle when fingerprint is running. - boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon; - mTrustDrawable.setTrustManaged(trustManaged); - updateLockIconClickability(); - } - public KeyguardAffordanceView getPhoneView() { return mPhoneImageView; } @@ -503,7 +428,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onUnlockMethodStateChanged() { - updateLockIcon(); + mLockIcon.update(); updateCameraVisibility(); } @@ -563,9 +488,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private final Runnable mTransientFpErrorClearRunnable = new Runnable() { @Override public void run() { - mTransientFpError = false; + mLockIcon.setTransientFpError(false); mIndicationController.hideTransientIndication(); - updateLockIcon(); } }; @@ -578,17 +502,17 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onScreenTurnedOn() { - updateLockIcon(); + mLockIcon.update(); } @Override public void onScreenTurnedOff(int why) { - updateLockIcon(); + mLockIcon.update(); } @Override public void onKeyguardVisibilityChanged(boolean showing) { - updateLockIcon(); + mLockIcon.update(); } @Override @@ -597,24 +521,21 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onFingerprintRunningStateChanged(boolean running) { - updateLockIcon(); + mLockIcon.update(); } @Override public void onFingerprintHelp(int msgId, String helpString) { - mTransientFpError = true; + mLockIcon.setTransientFpError(true); mIndicationController.showTransientIndication(helpString, getResources().getColor(R.color.system_warning_color, null)); removeCallbacks(mTransientFpErrorClearRunnable); postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT); - updateLockIcon(); } @Override public void onFingerprintError(int msgId, String errString) { // TODO: Go to bouncer if this is "too many attempts" (lockout) error. - Log.i(TAG, "FP Error: " + errString); - updateLockIcon(); } }; @@ -622,29 +543,4 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL KeyguardIndicationController keyguardIndicationController) { mIndicationController = keyguardIndicationController; } - - /** - * A wrapper around another Drawable that overrides the intrinsic size. - */ - private static class IntrinsicSizeDrawable extends InsetDrawable { - - private final int mIntrinsicWidth; - private final int mIntrinsicHeight; - - public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) { - super(drawable, 0); - mIntrinsicWidth = intrinsicWidth; - mIntrinsicHeight = intrinsicHeight; - } - - @Override - public int getIntrinsicWidth() { - return mIntrinsicWidth; - } - - @Override - public int getIntrinsicHeight() { - return mIntrinsicHeight; - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java new file mode 100644 index 0000000..66f3232 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -0,0 +1,212 @@ +/* + * 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.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.InsetDrawable; +import android.util.AttributeSet; +import android.view.View; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.R; +import com.android.systemui.statusbar.KeyguardAffordanceView; +import com.android.systemui.statusbar.policy.AccessibilityController; + +/** + * Manages the different states and animations of the unlock icon. + */ +public class LockIcon extends KeyguardAffordanceView { + + + private static final int STATE_LOCKED = 0; + private static final int STATE_LOCK_OPEN = 1; + private static final int STATE_FACE_UNLOCK = 2; + private static final int STATE_FINGERPRINT = 3; + private static final int STATE_FINGERPRINT_ERROR = 4; + + private int mLastState = 0; + private boolean mTransientFpError; + private final TrustDrawable mTrustDrawable; + private final UnlockMethodCache mUnlockMethodCache; + private AccessibilityController mAccessibilityController; + + public LockIcon(Context context, AttributeSet attrs) { + super(context, attrs); + mTrustDrawable = new TrustDrawable(context); + setBackground(mTrustDrawable); + mUnlockMethodCache = UnlockMethodCache.getInstance(context); + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (isShown()) { + mTrustDrawable.start(); + } else { + mTrustDrawable.stop(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mTrustDrawable.stop(); + } + + public void setTransientFpError(boolean transientFpError) { + mTransientFpError = transientFpError; + update(); + } + + public void update() { + boolean visible = isShown() && KeyguardUpdateMonitor.getInstance(mContext).isScreenOn(); + if (visible) { + mTrustDrawable.start(); + } else { + mTrustDrawable.stop(); + } + if (!visible) { + return; + } + // TODO: Real icon for facelock. + int state = getState(); + boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR; + if (state != mLastState) { + int iconRes = getAnimationResForTransition(mLastState, state); + if (iconRes == -1) { + iconRes = getIconForState(state); + } + Drawable icon = mContext.getDrawable(iconRes); + AnimatedVectorDrawable animation = null; + if (icon instanceof AnimatedVectorDrawable) { + animation = (AnimatedVectorDrawable) icon; + } + int iconHeight = getResources().getDimensionPixelSize( + R.dimen.keyguard_affordance_icon_height); + int iconWidth = getResources().getDimensionPixelSize( + R.dimen.keyguard_affordance_icon_width); + if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight + || icon.getIntrinsicWidth() != iconWidth)) { + icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight); + } + setPaddingRelative(0, 0, 0, anyFingerprintIcon + ? getResources().getDimensionPixelSize( + R.dimen.fingerprint_icon_additional_padding) + : 0); + setRestingAlpha( + anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT); + setImageDrawable(icon); + if (animation != null) { + animation.start(); + } + } + + // Hide trust circle when fingerprint is running. + boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon; + mTrustDrawable.setTrustManaged(trustManaged); + mLastState = state; + updateClickability(); + } + + private void updateClickability() { + if (mAccessibilityController == null) { + return; + } + boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled(); + boolean clickToForceLock = mUnlockMethodCache.isTrustManaged() + && !mAccessibilityController.isAccessibilityEnabled(); + boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged() + && !clickToForceLock; + setClickable(clickToForceLock || clickToUnlock); + setLongClickable(longClickToForceLock); + setFocusable(mAccessibilityController.isAccessibilityEnabled()); + } + + public void setAccessibilityController(AccessibilityController accessibilityController) { + mAccessibilityController = accessibilityController; + } + + private int getIconForState(int state) { + switch (state) { + case STATE_LOCKED: + return R.drawable.ic_lock_24dp; + case STATE_LOCK_OPEN: + return R.drawable.ic_lock_open_24dp; + case STATE_FACE_UNLOCK: + return com.android.internal.R.drawable.ic_account_circle; + case STATE_FINGERPRINT: + return R.drawable.ic_fingerprint; + case STATE_FINGERPRINT_ERROR: + return R.drawable.ic_fingerprint_error; + default: + throw new IllegalArgumentException(); + } + } + + private int getAnimationResForTransition(int oldState, int newState) { + if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) { + return R.drawable.lockscreen_fingerprint_error_state_animation; + } else { + return -1; + } + } + + private int getState() { + boolean fingerprintRunning = + KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning(); + if (mTransientFpError) { + return STATE_FINGERPRINT_ERROR; + } else if (fingerprintRunning) { + return STATE_FINGERPRINT; + } else if (mUnlockMethodCache.isFaceUnlockRunning()) { + return STATE_FACE_UNLOCK; + } else if (mUnlockMethodCache.isCurrentlyInsecure()) { + return STATE_LOCK_OPEN; + } else { + return STATE_LOCKED; + } + } + + /** + * A wrapper around another Drawable that overrides the intrinsic size. + */ + private static class IntrinsicSizeDrawable extends InsetDrawable { + + private final int mIntrinsicWidth; + private final int mIntrinsicHeight; + + public IntrinsicSizeDrawable(Drawable drawable, int intrinsicWidth, int intrinsicHeight) { + super(drawable, 0); + mIntrinsicWidth = intrinsicWidth; + mIntrinsicHeight = intrinsicHeight; + } + + @Override + public int getIntrinsicWidth() { + return mIntrinsicWidth; + } + + @Override + public int getIntrinsicHeight() { + return mIntrinsicHeight; + } + } +} 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 b87c25b..a8ecc42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -182,11 +182,11 @@ public class NotificationPanelView extends PanelView implements private float mKeyguardStatusBarAnimateAlpha = 1f; private int mOldLayoutDirection; - private HeadsUpTouchHelper mHeadsUpTouchHelper = new HeadsUpTouchHelper(); - private boolean mPinnedHeadsUpExist; - private boolean mExpansionIsFromHeadsUp; - private int mBottomBarHeight; + private HeadsUpTouchHelper mHeadsUpTouchHelper; + private boolean mIsExpansionFromHeadsUp; + private int mNavigationBarBottomHeight; private boolean mExpandingFromHeadsUp; + private boolean mCollapsedOnDown; private int mPositionMinSideMargin; private int mLastOrientation = -1; @@ -327,7 +327,7 @@ public class NotificationPanelView extends PanelView implements } else if (!mQsExpanded) { setQsExpansion(mQsMinExpansionHeight + mLastOverscroll); } - mNotificationStackScroller.setStackHeight(getExpandedHeight()); + updateStackHeight(getExpandedHeight()); updateHeader(); mNotificationStackScroller.updateIsSmallScreen( mHeader.getCollapsedHeight() + mQsPeekHeight); @@ -534,17 +534,16 @@ public class NotificationPanelView extends PanelView implements } @Override - public boolean - onInterceptTouchEvent(MotionEvent event) { + public boolean onInterceptTouchEvent(MotionEvent event) { if (mBlockTouches) { return false; } initDownStates(event); if (mHeadsUpTouchHelper.onInterceptTouchEvent(event)) { - mExpansionIsFromHeadsUp = true; + mIsExpansionFromHeadsUp = true; return true; } - if (!isShadeCollapsed() && onQsIntercept(event)) { + if (!isFullyCollapsed() && onQsIntercept(event)) { return true; } return super.onInterceptTouchEvent(event); @@ -641,6 +640,7 @@ public class NotificationPanelView extends PanelView implements mOnlyAffordanceInThisMotion = false; mQsTouchAboveFalsingThreshold = mQsFullyExpanded; mDozingOnDown = isDozing(); + mCollapsedOnDown = isFullyCollapsed(); } } @@ -695,7 +695,7 @@ public class NotificationPanelView extends PanelView implements return true; } mHeadsUpTouchHelper.onTouchEvent(event); - if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQSTouch(event)) { + if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) { return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { @@ -705,7 +705,7 @@ public class NotificationPanelView extends PanelView implements return true; } - private boolean handleQSTouch(MotionEvent event) { + private boolean handleQsTouch(MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f && mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded && mQsExpansionEnabled) { @@ -718,7 +718,7 @@ public class NotificationPanelView extends PanelView implements mInitialTouchY = event.getX(); mInitialTouchX = event.getY(); } - if (!isShadeCollapsed()) { + if (!isFullyCollapsed()) { handleQsDown(event); } if (!mQsExpandImmediate && mQsTracking) { @@ -731,7 +731,7 @@ public class NotificationPanelView extends PanelView implements || event.getActionMasked() == MotionEvent.ACTION_UP) { mConflictingQsExpansionGesture = false; } - if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isShadeCollapsed() + if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed() && mQsExpansionEnabled) { mTwoFingerQsExpandPossible = true; } @@ -1191,8 +1191,8 @@ public class NotificationPanelView extends PanelView implements updateEmptyShadeView(); mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling && mQsScrimEnabled - ? View.VISIBLE - : View.INVISIBLE); + ? View.VISIBLE + : View.INVISIBLE); if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) { mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */); } @@ -1386,7 +1386,7 @@ public class NotificationPanelView extends PanelView implements * @return Whether we should intercept a gesture to open Quick Settings. */ private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) { - if (!mQsExpansionEnabled) { + if (!mQsExpansionEnabled || mCollapsedOnDown) { return false; } View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader; @@ -1457,12 +1457,12 @@ public class NotificationPanelView extends PanelView implements setQsExpansion(mQsMinExpansionHeight + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight)); } - mNotificationStackScroller.setStackHeight(expandedHeight); + updateStackHeight(expandedHeight); updateHeader(); updateUnlockIcon(); updateNotificationTranslucency(); - mHeadsUpManager.setIsExpanded(!isShadeCollapsed()); - mNotificationStackScroller.setShadeExpanded(!isShadeCollapsed()); + mHeadsUpManager.setIsExpanded(!isFullyCollapsed()); + mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed()); if (DEBUG) { invalidate(); } @@ -1535,21 +1535,19 @@ public class NotificationPanelView extends PanelView implements float alpha; if (mExpandingFromHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) { alpha = 1f; - if (mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) { - mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null); - } } else { alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight()) / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize() - mNotificationStackScroller.getCollapseSecondCardPadding()); alpha = Math.max(0, Math.min(alpha, 1)); alpha = (float) Math.pow(alpha, 0.75); - if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) { - mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null); - } else if (alpha == 1f - && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) { - mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null); - } + } + + if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) { + mNotificationStackScroller.setLayerType(LAYER_TYPE_HARDWARE, null); + } else if (alpha == 1f + && mNotificationStackScroller.getLayerType() == LAYER_TYPE_HARDWARE) { + mNotificationStackScroller.setLayerType(LAYER_TYPE_NONE, null); } mNotificationStackScroller.setAlpha(alpha); } @@ -1615,7 +1613,7 @@ public class NotificationPanelView extends PanelView implements } float stackTranslation = mNotificationStackScroller.getStackTranslation(); float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR; - if (mHeadsUpManager.hasPinnedHeadsUp() || mExpansionIsFromHeadsUp) { + if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) { translation = mNotificationStackScroller.getTopPadding() + stackTranslation - mNotificationTopPadding - mQsMinExpansionHeight; } @@ -1683,16 +1681,16 @@ public class NotificationPanelView extends PanelView implements mHeadsUpManager.onExpandingFinished(); mIsExpanding = false; mScrollYOverride = -1; - if (isShadeCollapsed()) { + if (isFullyCollapsed()) { setListening(false); } else { setListening(true); } mQsExpandImmediate = false; mTwoFingerQsExpandPossible = false; - mExpansionIsFromHeadsUp = false; - mNotificationStackScroller.setTrackingHeadsUp(mHeadsUpTouchHelper.isTrackingHeadsUp()); - mExpandingFromHeadsUp = mHeadsUpTouchHelper.isTrackingHeadsUp(); + mIsExpansionFromHeadsUp = false; + mNotificationStackScroller.setTrackingHeadsUp(false); + mExpandingFromHeadsUp = false; } private void setListening(boolean listening) { @@ -1793,13 +1791,13 @@ public class NotificationPanelView extends PanelView implements @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - mBottomBarHeight = insets.getSystemWindowInsetBottom(); + mNavigationBarBottomHeight = insets.getSystemWindowInsetBottom(); updateMaxHeadsUpTranslation(); return insets; } private void updateMaxHeadsUpTranslation() { - mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mBottomBarHeight); + mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mNavigationBarBottomHeight); } @Override @@ -2160,48 +2158,43 @@ public class NotificationPanelView extends PanelView implements } @Override - public void OnPinnedHeadsUpExistChanged(final boolean exist, boolean changeImmediatly) { - if (exist != mPinnedHeadsUpExist) { - mPinnedHeadsUpExist = exist; - if (exist) { - mHeadsUpExistenceChangedRunnable.run(); - updateNotificationTranslucency(); - } else { - mNotificationStackScroller.performOnAnimationFinished( - mHeadsUpExistenceChangedRunnable); - } + public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) { + if (inPinnedMode) { + mHeadsUpExistenceChangedRunnable.run(); + updateNotificationTranslucency(); + } else { + mNotificationStackScroller.runAfterAnimationFinished( + mHeadsUpExistenceChangedRunnable); } } @Override - public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) { - if (isHeadsUp) { - mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true); - } + public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true); } @Override - public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { - mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp); + public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { } @Override - protected boolean isShadeCollapsed() { - return mExpandedHeight == 0; + public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { + mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp); } @Override public void setHeadsUpManager(HeadsUpManager headsUpManager) { super.setHeadsUpManager(headsUpManager); - mHeadsUpTouchHelper.bind(headsUpManager, mNotificationStackScroller, this); + mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller, + this); } public void setTrackingHeadsUp(boolean tracking) { if (tracking) { - // otherwise we update the state when the expansion is finished mNotificationStackScroller.setTrackingHeadsUp(true); mExpandingFromHeadsUp = true; } + // otherwise we update the state when the expansion is finished } @Override @@ -2241,4 +2234,9 @@ public class NotificationPanelView extends PanelView implements mScrollView.setTranslationX(translation); mHeader.setTranslationX(translation); } + + private void updateStackHeight(float stackHeight) { + mNotificationStackScroller.setStackHeight(stackHeight); + updateKeyguardBottomAreaAlpha(); + } } 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 4452dd7..85f312c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -46,13 +46,13 @@ import java.io.PrintWriter; public abstract class PanelView extends FrameLayout { public static final boolean DEBUG = PanelBar.DEBUG; public static final String TAG = PanelView.class.getSimpleName(); - protected HeadsUpManager mHeadsUpManager; - private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); } protected PhoneStatusBar mStatusBar; + protected HeadsUpManager mHeadsUpManager; + private float mPeekHeight; private float mHintDistance; private int mEdgeTapAreaWidth; @@ -242,15 +242,15 @@ public abstract class PanelView extends FrameLayout { final float y = event.getY(pointerIndex); if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - mGestureWaitForTouchSlop = isShadeCollapsed() || hasConflictingGestures(); - mIgnoreXTouchSlop = isShadeCollapsed() || shouldGestureIgnoreXTouchSlop(x, y); + mGestureWaitForTouchSlop = isFullyCollapsed() || hasConflictingGestures(); + mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y); } switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: startExpandMotion(x, y, false /* startTracking */, mExpandedHeight); mJustPeeked = false; - mPanelClosedOnDown = isShadeCollapsed(); + mPanelClosedOnDown = isFullyCollapsed(); mHasLayoutedSinceDown = false; mUpdateFlingOnLayout = false; mMotionAborted = false; @@ -268,7 +268,7 @@ public abstract class PanelView extends FrameLayout { || mPeekPending || mPeekAnimator != null; onTrackingStarted(); } - if (isShadeCollapsed()) { + if (isFullyCollapsed()) { schedulePeek(); } break; @@ -472,7 +472,7 @@ public abstract class PanelView extends FrameLayout { mTouchSlopExceeded = false; mJustPeeked = false; mMotionAborted = false; - mPanelClosedOnDown = isShadeCollapsed(); + mPanelClosedOnDown = isFullyCollapsed(); mHasLayoutedSinceDown = false; mUpdateFlingOnLayout = false; mTouchAboveFalsingThreshold = false; @@ -707,7 +707,7 @@ public abstract class PanelView extends FrameLayout { // If the user isn't actively poking us, let's update the height if ((!mTracking || isTrackingBlocked()) && mHeightAnimator == null - && !isShadeCollapsed() + && !isFullyCollapsed() && currentMaxPanelHeight != mExpandedHeight && !mPeekPending && mPeekAnimator == null @@ -1057,8 +1057,6 @@ public abstract class PanelView extends FrameLayout { */ protected abstract int getClearAllHeight(); - protected abstract boolean isShadeCollapsed(); - public void setHeadsUpManager(HeadsUpManager headsUpManager) { mHeadsUpManager = headsUpManager; } 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 6b17589..9a6a80e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1152,11 +1152,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void removeNotification(String key, RankingMap ranking) { - boolean defferRemoval = false; + boolean deferRemoval = false; if (mHeadsUpManager.isHeadsUp(key)) { - defferRemoval = !mHeadsUpManager.removeNotification(key); + deferRemoval = !mHeadsUpManager.removeNotification(key); } - if (defferRemoval) { + if (deferRemoval) { mLatestRankingMap = ranking; mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key)); return; @@ -1293,13 +1293,20 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, updateClearAll(); updateEmptyShadeView(); - // Disable QS if device not provisioned. - // If the user switcher is simple then disable QS during setup because - // the user intends to use the lock screen user switcher, QS in not needed. + updateQsExpansionEnabled(); + mShadeUpdates.check(); + } + + /** + * Disable QS if device not provisioned. + * If the user switcher is simple then disable QS during setup because + * the user intends to use the lock screen user switcher, QS in not needed. + */ + private void updateQsExpansionEnabled() { mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && (mUserSetup || mUserSwitcherController == null - || !mUserSwitcherController.isSimpleUserSwitcher())); - mShadeUpdates.check(); + || !mUserSwitcherController.isSimpleUserSwitcher()) + && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)); } private void updateNotificationShadeForChildren() { @@ -1732,6 +1739,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, flagdbg.append(((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " "); flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search"); flagdbg.append(((diff1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " "); + flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS" + : "quick_settings"); + flagdbg.append(((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " "); flagdbg.append(">"); Log.d(TAG, flagdbg.toString()); @@ -1780,6 +1790,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; mHeadsUpObserver.onChange(true); } + + if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { + updateQsExpansionEnabled(); + } } @Override @@ -1838,8 +1852,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) { - if (exist) { + public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { + if (inPinnedMode) { mStatusBarWindowManager.setHeadsUpShowing(true); } else { Runnable endRunnable = new Runnable() { @@ -1850,20 +1864,25 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } }; - if (changeImmediatly) { + if (!mNotificationPanel.isFullyCollapsed()) { endRunnable.run(); } else { - mStackScroller.performOnAnimationFinished(endRunnable); + mStackScroller.runAfterAnimationFinished(endRunnable); } } } @Override - public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) { + public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + dismissVolumeDialog(); } @Override - public void OnHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { + public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + } + + @Override + public void onHeadsUpStateChanged(Entry entry, boolean isHeadsUp) { if (!isHeadsUp && mHeadsUpEntriesToRemoveOnSwitch.contains(entry)) { removeNotification(entry.key, mLatestRankingMap); mHeadsUpEntriesToRemoveOnSwitch.remove(entry); @@ -1880,10 +1899,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, boolean alertAgain) { final boolean wasHeadsUp = isHeadsUp(key); if (wasHeadsUp) { - mHeadsUpManager.updateNotification(entry, alertAgain); if (!shouldInterrupt) { // We don't want this to be interrupting anymore, lets remove it mHeadsUpManager.removeNotification(key); + } else { + mHeadsUpManager.updateNotification(entry, alertAgain); } } else if (shouldInterrupt && alertAgain) { // This notification was updated to be a heads-up, show it! @@ -1929,7 +1949,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void escalateHeadsUp() { + public void maybeEscalateHeadsUp() { TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries(); for (HeadsUpManager.HeadsUpEntry entry : entries) { final StatusBarNotification sbn = entry.entry.notification; @@ -2358,13 +2378,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } // manually dismiss the volume panel when interacting with the nav bar if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) { - if (mVolumeComponent != null) { - mVolumeComponent.dismissNow(); - } + dismissVolumeDialog(); } checkBarModes(); } + private void dismissVolumeDialog() { + if (mVolumeComponent != null) { + mVolumeComponent.dismissNow(); + } + } + private void resumeSuspendedAutohide() { if (mAutohideSuspended) { scheduleAutohide(); @@ -2852,6 +2876,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } catch (RemoteException e) { // Ignore. } + setNotificationsShown(newlyVisibleAr); } // State logging 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 fb42ba1..0e8e844 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -224,14 +224,14 @@ public class PhoneStatusBarPolicy { } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) { zenVisible = true; zenIconId = R.drawable.stat_sys_zen_none; - zenDescription = mContext.getString(R.string.zen_no_interruptions); + zenDescription = mContext.getString(R.string.interruption_level_none); } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { zenVisible = true; zenIconId = R.drawable.stat_sys_zen_important; - zenDescription = mContext.getString(R.string.zen_important_interruptions); + zenDescription = mContext.getString(R.string.interruption_level_priority); } - if (DndTile.isVisible(mContext) + if (DndTile.isVisible(mContext) && !DndTile.isCombinedIcon(mContext) && audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { volumeVisible = true; volumeIconId = R.drawable.stat_sys_ringer_silent; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index e701783..e6edbea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -80,7 +80,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, private float mCurrentInFrontAlpha; private float mCurrentBehindAlpha; private float mCurrentHeadsUpAlpha = 1; - private int mAmountOfPinnedHeadsUps; + private int mPinnedHeadsUpCount; private float mTopHeadsUpDragAmount; private View mDraggedHeadsUpView; @@ -347,25 +347,27 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } @Override - public void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly) { + public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) { } @Override - public void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp) { - if (isHeadsUp) { - mAmountOfPinnedHeadsUps++; - } else { - mAmountOfPinnedHeadsUps--; - if (headsUp == mDraggedHeadsUpView) { - mDraggedHeadsUpView = null; - mTopHeadsUpDragAmount = 0.0f; - } + public void onHeadsUpPinned(ExpandableNotificationRow headsUp) { + mPinnedHeadsUpCount++; + updateHeadsUpScrim(true); + } + + @Override + public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) { + mPinnedHeadsUpCount--; + if (headsUp == mDraggedHeadsUpView) { + mDraggedHeadsUpView = null; + mTopHeadsUpDragAmount = 0.0f; } updateHeadsUpScrim(true); } @Override - public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { + public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { } private void updateHeadsUpScrim(boolean animate) { @@ -374,12 +376,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, TAG_KEY_ANIM); float animEndValue = -1; if (previousAnimator != null) { - if ((animate || alpha == mCurrentHeadsUpAlpha)) { - // lets cancel any running animators + if (animate || alpha == mCurrentHeadsUpAlpha) { previousAnimator.cancel(); } - animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, - TAG_HUN_START_ALPHA); + animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_START_ALPHA); } if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) { if (animate) { @@ -390,7 +390,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, if (previousAnimator != null) { float previousStartValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_START_ALPHA); - float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, + float previousEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_END_ALPHA); // we need to increase all animation keyframes of the previous animator by the // relative change to the end value @@ -410,6 +410,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } } + /** + * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means + * the heads up is in its resting space and 1 means it's fully dragged out. + * + * @param draggedHeadsUpView the dragged view + * @param topHeadsUpDragAmount how far is it dragged + */ public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) { mTopHeadsUpDragAmount = topHeadsUpDragAmount; mDraggedHeadsUpView = draggedHeadsUpView; @@ -417,9 +424,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, } private float calculateHeadsUpAlpha() { - if (mAmountOfPinnedHeadsUps >= 2) { + if (mPinnedHeadsUpCount >= 2) { return 1.0f; - } else if (mAmountOfPinnedHeadsUps == 0) { + } else if (mPinnedHeadsUpCount == 0) { return 0.0f; } else { return 1.0f - mTopHeadsUpDragAmount; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java index 4a43c47..45c8938 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java @@ -27,6 +27,7 @@ import android.provider.MediaStore; import android.util.Log; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import java.util.HashMap; import java.util.List; @@ -228,7 +229,7 @@ public class SecureCameraLaunchManager { // Get the list of applications that can handle the intent. final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser()); + intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser()); if (appList.size() == 0) { if (DEBUG) Log.d(TAG, "No targets found for secure camera intent"); return false; @@ -237,7 +238,7 @@ public class SecureCameraLaunchManager { // Get the application that the intent resolves to. ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, - mLockPatternUtils.getCurrentUser()); + KeyguardUpdateMonitor.getCurrentUser()); if (resolved == null || resolved.activityInfo == null) { return false; 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 65cd268..66d71f6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java @@ -80,8 +80,8 @@ public class UnlockMethodCache { } private void update(boolean updateAlways) { - int user = mLockPatternUtils.getCurrentUser(); - boolean secure = mLockPatternUtils.isSecure(); + int user = KeyguardUpdateMonitor.getCurrentUser(); + boolean secure = mLockPatternUtils.isSecure(user); boolean currentlyInsecure = !secure || mKeyguardUpdateMonitor.getUserHasTrust(user); boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user); boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index b4e4773..0db9221 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * 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. @@ -35,11 +35,16 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Stack; import java.util.TreeSet; +/** + * A manager which handles heads up notifications which is a special mode where + * they simply peek from the top of the screen. + */ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener { private static final String TAG = "HeadsUpManager"; private static final boolean DEBUG = false; @@ -48,7 +53,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL private final int mHeadsUpNotificationDecay; private final int mMinimumDisplayTime; - private final int mTouchSensitivityDelay; + private final int mTouchAcceptanceDelay; private final ArrayMap<String, Long> mSnoozedPackages; private final HashSet<OnHeadsUpChangedListener> mListeners = new HashSet<>(); private final int mDefaultSnoozeLengthMs; @@ -67,13 +72,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL @Override public boolean release(HeadsUpEntry instance) { - instance.removeAutoCancelCallbacks(); + instance.reset(); mPoolObjects.push(instance); return true; } }; - private PhoneStatusBar mBar; private int mSnoozeLengthMs; private ContentObserver mSettingsObserver; @@ -86,13 +90,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL private boolean mTrackingHeadsUp; private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>(); private boolean mIsExpanded; - private boolean mHasPinnedHeadsUp; + private boolean mHasPinnedNotification; private int[] mTmpTwoArray = new int[2]; public HeadsUpManager(final Context context, ViewTreeObserver observer) { Resources resources = context.getResources(); - mTouchSensitivityDelay = resources.getInteger(R.integer.heads_up_sensitivity_delay); - if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay); + mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay); mSnoozedPackages = new ArrayMap<>(); mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms); mSnoozeLengthMs = mDefaultSnoozeLengthMs; @@ -116,7 +119,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL context.getContentResolver().registerContentObserver( Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false, mSettingsObserver); - if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs); observer.addOnComputeInternalInsetsListener(this); } @@ -154,7 +156,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL if (alert) { HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key); headsUpEntry.updateEntry(); - setEntryToShade(headsUpEntry, mIsExpanded, false /* justAdded */, false); + setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */); } } @@ -165,22 +167,23 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL headsUpEntry.setEntry(entry); mHeadsUpEntries.put(entry.key, headsUpEntry); entry.row.setHeadsUp(true); - setEntryToShade(headsUpEntry, mIsExpanded /* inShade */, true /* justAdded */, false); + setEntryPinned(headsUpEntry, !mIsExpanded /* isPinned */); for (OnHeadsUpChangedListener listener : mListeners) { - listener.OnHeadsUpStateChanged(entry, true); + listener.onHeadsUpStateChanged(entry, true); } entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); } - private void setEntryToShade(HeadsUpEntry headsUpEntry, boolean inShade, boolean justAdded, - boolean forceImmediate) { + private void setEntryPinned(HeadsUpEntry headsUpEntry, boolean isPinned) { ExpandableNotificationRow row = headsUpEntry.entry.row; - if (row.isInShade() != inShade || justAdded) { - row.setInShade(inShade); - if (!justAdded || !inShade) { - updatePinnedHeadsUpState(forceImmediate); - for (OnHeadsUpChangedListener listener : mListeners) { - listener.OnHeadsUpPinnedChanged(row, !inShade); + if (row.isPinned() != isPinned) { + row.setPinned(isPinned); + updatePinnedMode(); + for (OnHeadsUpChangedListener listener : mListeners) { + if (isPinned) { + listener.onHeadsUpPinned(row); + } else { + listener.onHeadsUpUnPinned(row); } } } @@ -189,24 +192,23 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL private void removeHeadsUpEntry(NotificationData.Entry entry) { HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key); mSortedEntries.remove(remove); - mEntryPool.release(remove); entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); entry.row.setHeadsUp(false); - setEntryToShade(remove, true /* inShade */, false /* justAdded */, - false /* forceImmediate */); + setEntryPinned(remove, false /* isPinned */); for (OnHeadsUpChangedListener listener : mListeners) { - listener.OnHeadsUpStateChanged(entry, false); + listener.onHeadsUpStateChanged(entry, false); } + mEntryPool.release(remove); } - private void updatePinnedHeadsUpState(boolean forceImmediate) { - boolean hasPinnedHeadsUp = hasPinnedHeadsUpInternal(); - if (hasPinnedHeadsUp == mHasPinnedHeadsUp) { + private void updatePinnedMode() { + boolean hasPinnedNotification = hasPinnedNotificationInternal(); + if (hasPinnedNotification == mHasPinnedNotification) { return; } - mHasPinnedHeadsUp = hasPinnedHeadsUp; - for (OnHeadsUpChangedListener listener :mListeners) { - listener.OnPinnedHeadsUpExistChanged(hasPinnedHeadsUp, forceImmediate); + mHasPinnedNotification = hasPinnedNotification; + for (OnHeadsUpChangedListener listener : mListeners) { + listener.onHeadsUpPinnedModeChanged(hasPinnedNotification); } } @@ -222,7 +224,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL releaseImmediately(key); return true; } else { - getHeadsUpEntry(key).hideAsSoonAsPossible(); + getHeadsUpEntry(key).removeAsSoonAsPossible(); return false; } } @@ -245,14 +247,13 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return mHeadsUpEntries.containsKey(key); } - /** * Push any current Heads Up notification down into the shade. */ public void releaseAllImmediately() { if (DEBUG) Log.v(TAG, "releaseAllImmediately"); - HashSet<String> keys = new HashSet<>(mHeadsUpEntries.keySet()); - for (String key: keys) { + ArrayList<String> keys = new ArrayList<>(mHeadsUpEntries.keySet()); + for (String key : keys) { releaseImmediately(key); } } @@ -280,7 +281,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public void snooze() { - for (String key: mHeadsUpEntries.keySet()) { + for (String key : mHeadsUpEntries.keySet()) { HeadsUpEntry entry = mHeadsUpEntries.get(key); String packageName = entry.entry.notification.getPackageName(); mSnoozedPackages.put(snoozeKey(packageName, mUser), @@ -310,8 +311,11 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } /** + * Decides whether a click is invalid for a notification, i.e it has not been shown long enough + * that a user might have consciously clicked on it. + * * @param key the key of the touched notification - * @return whether the touch is valid and should not be discarded + * @return whether the touch is invalid and should be discarded */ public boolean shouldSwallowClick(String key) { HeadsUpEntry entry = mHeadsUpEntries.get(key); @@ -322,14 +326,14 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (!mIsExpanded && mHasPinnedHeadsUp) { + if (!mIsExpanded && mHasPinnedNotification) { int minX = Integer.MAX_VALUE; int maxX = 0; int minY = Integer.MAX_VALUE; int maxY = 0; - for (HeadsUpEntry entry: mSortedEntries) { + for (HeadsUpEntry entry : mSortedEntries) { ExpandableNotificationRow row = entry.entry.row; - if (!row.isInShade()) { + if (row.isPinned()) { row.getLocationOnScreen(mTmpTwoArray); minX = Math.min(minX, mTmpTwoArray[0]); minY = Math.min(minY, 0); @@ -349,7 +353,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("HeadsUpManager state:"); - pw.print(" mTouchSensitivityDelay="); pw.println(mTouchSensitivityDelay); + pw.print(" mTouchAcceptanceDelay="); pw.println(mTouchAcceptanceDelay); pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs); pw.print(" now="); pw.println(SystemClock.elapsedRealtime()); pw.print(" mUser="); pw.println(mUser); @@ -365,38 +369,32 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public boolean hasPinnedHeadsUp() { - return mHasPinnedHeadsUp; + return mHasPinnedNotification; } - private boolean hasPinnedHeadsUpInternal() { - for (String key: mHeadsUpEntries.keySet()) { + private boolean hasPinnedNotificationInternal() { + for (String key : mHeadsUpEntries.keySet()) { HeadsUpEntry entry = mHeadsUpEntries.get(key); - if (!entry.entry.row.isInShade()) { + if (entry.entry.row.isPinned()) { return true; } } return false; } - public void addSwipedOutKey(String key) { + /** + * Notifies that a notification was swiped out and will be removed. + * + * @param key the notification key + */ + public void addSwipedOutNotification(String key) { mSwipedOutKeys.add(key); } - public float getHighestPinnedHeadsUp() { - float max = 0; - for (HeadsUpEntry entry: mSortedEntries) { - if (!entry.entry.row.isInShade()) { - max = Math.max(max, entry.entry.row.getActualHeight()); - } - } - return max; - } - - public void releaseAllToShade() { - for (String key: mHeadsUpEntries.keySet()) { + public void unpinAll() { + for (String key : mHeadsUpEntries.keySet()) { HeadsUpEntry entry = mHeadsUpEntries.get(key); - setEntryToShade(entry, true /* toShade */, false /* justAdded */, - true /* forceImmediate */); + setEntryPinned(entry, false /* isPinned */); } } @@ -420,7 +418,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL if (isExpanded != mIsExpanded) { mIsExpanded = isExpanded; if (isExpanded) { - releaseAllToShade(); + unpinAll(); } } } @@ -430,6 +428,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return topEntry != null ? topEntry.entry.row.getHeadsUpHeight() : 0; } + /** + * Compare two entries and decide how they should be ranked. + * + * @return -1 if the first argument should be ranked higher than the second, 1 if the second + * one should be ranked higher and 0 if they are equal. + */ public int compare(NotificationData.Entry a, NotificationData.Entry b) { HeadsUpEntry aEntry = getHeadsUpEntry(a.key); HeadsUpEntry bEntry = getHeadsUpEntry(b.key); @@ -439,6 +443,11 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return aEntry.compareTo(bEntry); } + + /** + * This represents a notification and how long it is in a heads up mode. It also manages its + * lifecycle automatically when created. + */ public class HeadsUpEntry implements Comparable<HeadsUpEntry> { public NotificationData.Entry entry; public long postTime; @@ -449,7 +458,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL this.entry = entry; // The actual post time will be just after the heads-up really slided in - postTime = mClock.currentTimeMillis() + mTouchSensitivityDelay; + postTime = mClock.currentTimeMillis() + mTouchAcceptanceDelay; mRemoveHeadsUpRunnable = new Runnable() { @Override public void run() { @@ -467,7 +476,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL long currentTime = mClock.currentTimeMillis(); earliestRemovaltime = currentTime + mMinimumDisplayTime; postTime = Math.max(postTime, currentTime); - removeAutoCancelCallbacks(); + removeAutoRemovalCallbacks(); if (canEntryDecay()) { long finishTime = postTime + mHeadsUpNotificationDecay; long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime); @@ -487,7 +496,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL : -1; } - public void removeAutoCancelCallbacks() { + public void removeAutoRemovalCallbacks() { mHandler.removeCallbacks(mRemoveHeadsUpRunnable); } @@ -495,11 +504,17 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL return earliestRemovaltime < mClock.currentTimeMillis(); } - public void hideAsSoonAsPossible() { - removeAutoCancelCallbacks(); + public void removeAsSoonAsPossible() { + removeAutoRemovalCallbacks(); mHandler.postDelayed(mRemoveHeadsUpRunnable, earliestRemovaltime - mClock.currentTimeMillis()); } + + public void reset() { + removeAutoRemovalCallbacks(); + entry = null; + mRemoveHeadsUpRunnable = null; + } } /** @@ -519,8 +534,29 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public interface OnHeadsUpChangedListener { - void OnPinnedHeadsUpExistChanged(boolean exist, boolean changeImmediatly); - void OnHeadsUpPinnedChanged(ExpandableNotificationRow headsUp, boolean isHeadsUp); - void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp); + /** + * The state whether there exist pinned heads-ups or not changed. + * + * @param inPinnedMode whether there are any pinned heads-ups + */ + void onHeadsUpPinnedModeChanged(boolean inPinnedMode); + + /** + * A notification was just pinned to the top. + */ + void onHeadsUpPinned(ExpandableNotificationRow headsUp); + + /** + * A notification was just unpinned from the top. + */ + void onHeadsUpUnPinned(ExpandableNotificationRow headsUp); + + /** + * A notification just became a heads up or turned back to its normal state. + * + * @param entry the entry of the changed notification + * @param isHeadsUp whether the notification is now a headsUp notification + */ + void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java index 0dce82f..5d89e2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java @@ -26,6 +26,7 @@ import android.view.LayoutInflater; import android.view.View; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.statusbar.phone.KeyguardPreviewContainer; import java.util.List; @@ -80,13 +81,13 @@ public class PreviewInflater { WidgetInfo info = new WidgetInfo(); PackageManager packageManager = mContext.getPackageManager(); final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser()); + intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser()); if (appList.size() == 0) { return null; } ResolveInfo resolved = packageManager.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, - mLockPatternUtils.getCurrentUser()); + KeyguardUpdateMonitor.getCurrentUser()); if (wouldLaunchResolverActivity(resolved, appList)) { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index 67cc788..9d84a85 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -35,6 +35,7 @@ public interface ZenModeController { boolean isZenAvailable(); ComponentName getEffectsSuppressor(); boolean isCountdownConditionSupported(); + int getCurrentUser(); public static class Callback { public void onZenChanged(int zen) {} @@ -45,4 +46,5 @@ public interface ZenModeController { public void onManualRuleChanged(ZenRule rule) {} public void onConfigChanged(ZenModeConfig config) {} } + }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 830a197..5b80ac2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.NotificationManager; import android.content.BroadcastReceiver; @@ -159,6 +160,11 @@ public class ZenModeControllerImpl implements ZenModeController { .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH); } + @Override + public int getCurrentUser() { + return ActivityManager.getCurrentUser(); + } + private void fireNextAlarmChanged() { for (Callback cb : mCallbacks) { cb.onNextAlarmChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java new file mode 100644 index 0000000..05c0099 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java @@ -0,0 +1,51 @@ +/* + * 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.stack; + +import android.graphics.Path; +import android.view.animation.PathInterpolator; + +/** + * An interpolator specifically designed for the appear animation of heads up notifications. + */ +public class HeadsUpAppearInterpolator extends PathInterpolator { + public HeadsUpAppearInterpolator() { + super(getAppearPath()); + } + + private static Path getAppearPath() { + Path path = new Path(); + path.moveTo(0, 0); + float x1 = 250f; + float x2 = 150f; + float x3 = 100f; + float y1 = 90f; + float y2 = 78f; + float y3 = 80f; + float xTot = (x1 + x2 + x3); + path.cubicTo(x1 * 0.9f / xTot, 0f, + x1 * 0.8f / xTot, y1 / y3, + x1 / xTot , y1 / y3); + path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3, + (x1 + x2 * 0.2f) / xTot, y2 / y3, + (x1 + x2) / xTot, y2 / y3); + path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3, + (x1 + x2 + x3 * 0.2f) / xTot, 1f, + 1f, 1f); + return path; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 88fc602..a1b0cae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -204,7 +204,6 @@ public class NotificationStackScrollLayout extends ViewGroup private ViewGroup mScrollView; private boolean mInterceptDelegateEnabled; private boolean mDelegateToScrollView; - private boolean mDisallowScrollingInThisMotion; private long mGoToFullShadeDelay; private ViewTreeObserver.OnPreDrawListener mChildrenUpdater @@ -487,9 +486,9 @@ public class NotificationStackScrollLayout extends ViewGroup int stackHeight; float paddingOffset; boolean trackingHeadsUp = mTrackingHeadsUp; - int normalExpandPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight() + int normalUnfoldPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight() : minStackHeight; - if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalExpandPositionStart + if (newStackHeight - mTopPadding - mTopPaddingOverflow >= normalUnfoldPositionStart || getNotGoneChildCount() == 0) { paddingOffset = mTopPaddingOverflow; stackHeight = newStackHeight; @@ -582,7 +581,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (v instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) v; if (row.isHeadsUp()) { - mHeadsUpManager.addSwipedOutKey(row.getStatusBarNotification().getKey()); + mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey()); } } final View veto = v.findViewById(R.id.veto); @@ -626,10 +625,10 @@ public class NotificationStackScrollLayout extends ViewGroup requestChildrenUpdate(); } - public boolean isPinnedHeadsUp(View v) { + public static boolean isPinnedHeadsUp(View v) { if (v instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) v; - return row.isHeadsUp() && !row.isInShade(); + return row.isHeadsUp() && row.isPinned(); } return false; } @@ -711,7 +710,7 @@ public class NotificationStackScrollLayout extends ViewGroup if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) { if (slidingChild instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild; - if (row.isHeadsUp() && !row.isInShade() + if (row.isHeadsUp() && row.isPinned() && mHeadsUpManager.getTopEntry().entry.row != row) { continue; } @@ -812,7 +811,8 @@ public class NotificationStackScrollLayout extends ViewGroup } handleEmptySpaceClick(ev); boolean expandWantsIt = false; - if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) { + if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion + && isScrollingEnabled()) { if (isCancelOrUp) { mExpandHelper.onlyObserveMovements(false); } @@ -824,7 +824,8 @@ public class NotificationStackScrollLayout extends ViewGroup } } boolean scrollerWantsIt = false; - if (!mSwipingInProgress && !mExpandingNotification && !mDisallowScrollingInThisMotion) { + if (mIsExpanded && !mSwipingInProgress && !mExpandingNotification + && !mDisallowScrollingInThisMotion) { scrollerWantsIt = onScrollTouch(ev); } boolean horizontalSwipeWantsIt = false; @@ -1872,15 +1873,15 @@ public class NotificationStackScrollLayout extends ViewGroup boolean onBottom = false; if (!mIsExpanded && !isHeadsUp) { type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR; - } else if (mAddedHeadsUpChildren.contains(row) || (!row.isInShade() && !mIsExpanded)) { - if (!row.isInShade() || shouldHunAppearFromBottom(row)) { + } else if (mAddedHeadsUpChildren.contains(row) || (row.isPinned() && !mIsExpanded)) { + if (row.isPinned() || shouldHunAppearFromBottom(row)) { // Our custom add animation type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR; } else { // Normal add animation type = AnimationEvent.ANIMATION_TYPE_ADD; } - onBottom = row.isInShade(); + onBottom = !row.isPinned(); } AnimationEvent event = new AnimationEvent(row, type); event.headsUpFromBottom = onBottom; @@ -2670,7 +2671,7 @@ public class NotificationStackScrollLayout extends ViewGroup } } - public void performOnAnimationFinished(Runnable runnable) { + public void runAfterAnimationFinished(Runnable runnable) { mAnimationFinishedRunnables.add(runnable); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 2a49a4c..202063a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -311,7 +311,8 @@ public class StackScrollAlgorithm { StackViewState viewState = resultState.getViewStateForView( nextChild); // The child below the dragged one must be fully visible - if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) { + if (!NotificationStackScrollLayout.isPinnedHeadsUp(draggedView) + || NotificationStackScrollLayout.isPinnedHeadsUp(nextChild)) { viewState.alpha = 1; } } @@ -324,14 +325,6 @@ public class StackScrollAlgorithm { } } - private boolean isPinnedHeadsUpView(View view) { - if (view instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) view; - return row.isHeadsUp() && !row.isInShade(); - } - return false; - } - /** * Update the visible children on the state. */ @@ -380,7 +373,7 @@ public class StackScrollAlgorithm { /** * Determine the positions for the views. This is the main part of the algorithm. * - * @param resultState The result state to update if a change to the properties of a child occurs + * @param resultState The result state to update if a change to the properties of a child occurs * @param algorithmState The state in which the current pass of the algorithm is currently in * @param ambientState The current ambient state */ @@ -515,11 +508,12 @@ public class StackScrollAlgorithm { } StackViewState childState = resultState.getViewStateForView(row); boolean isTopEntry = topHeadsUpEntry == row; - if (!row.isInShade()) { + if (row.isPinned()) { childState.yTranslation = 0; childState.height = row.getHeadsUpHeight(); if (!isTopEntry) { - // Ensure that a headsUp is never below the topmost headsUp + // Ensure that a headsUp doesn't vertically extend further than the heads-up at + // the top most z-position StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry); childState.height = row.getHeadsUpHeight(); childState.yTranslation = topState.yTranslation + topState.height diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index f5d94c8..b9466d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -21,11 +21,9 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; -import android.graphics.Path; import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import android.view.animation.PathInterpolator; import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableNotificationRow; @@ -78,6 +76,7 @@ public class StackStateAnimator { private final Interpolator mFastOutSlowInInterpolator; private final Interpolator mHeadsUpAppearInterpolator; private final int mGoToFullShadeAppearingTranslation; + private final StackViewState mTmpState = new StackViewState(); public NotificationStackScrollLayout mHostLayout; private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents = new ArrayList<>(); @@ -95,7 +94,6 @@ public class StackStateAnimator { private ValueAnimator mTopOverScrollAnimator; private ValueAnimator mBottomOverScrollAnimator; private ExpandableNotificationRow mChildExpandingView; - private StackViewState mTmpState = new StackViewState(); private int mHeadsUpAppearHeightBottom; private boolean mShadeExpanded; @@ -106,25 +104,7 @@ public class StackStateAnimator { mGoToFullShadeAppearingTranslation = hostLayout.getContext().getResources().getDimensionPixelSize( R.dimen.go_to_full_shade_appearing_translation); - Path path = new Path(); - path.moveTo(0, 0); - float x1 = 250f; - float x2 = 150f; - float x3 = 100f; - float y1 = 90f; - float y2 = 78f; - float y3 = 80f; - float xTot = (x1 + x2 + x3); - path.cubicTo(x1 * 0.9f / xTot, 0f, - x1 * 0.8f / xTot, y1 / y3, - x1 / xTot , y1 / y3); - path.cubicTo((x1 + x2 * 0.4f) / xTot, y1 / y3, - (x1 + x2 * 0.2f) / xTot, y2 / y3, - (x1 + x2) / xTot, y2 / y3); - path.cubicTo((x1 + x2 + x3 * 0.4f) / xTot, y2 / y3, - (x1 + x2 + x3 * 0.2f) / xTot, 1f, - 1f, 1f); - mHeadsUpAppearInterpolator = new PathInterpolator(path); + mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator(); } public boolean isRunning() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index dda40d3..a5684a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -121,7 +121,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void escalateHeadsUp() { + public void maybeEscalateHeadsUp() { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 240c210..e6c95b5 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -24,12 +24,20 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.MoveCallback; +import android.os.Bundle; +import android.os.Handler; import android.os.UserHandle; import android.os.storage.DiskInfo; import android.os.storage.StorageEventListener; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.os.storage.VolumeRecord; +import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; +import android.util.SparseArray; import com.android.internal.R; import com.android.systemui.SystemUI; @@ -39,39 +47,93 @@ import java.util.List; public class StorageNotification extends SystemUI { private static final String TAG = "StorageNotification"; - private static final int NOTIF_ID = 0x53544f52; // STOR + private static final int PUBLIC_ID = 0x53505542; // SPUB + private static final int PRIVATE_ID = 0x53505256; // SPRV + private static final int DISK_ID = 0x5344534b; // SDSK + private static final int MOVE_ID = 0x534d4f56; // SMOV private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME"; // TODO: delay some notifications to avoid bumpy fast operations - // TODO: annoy user when private media is missing private NotificationManager mNotificationManager; private StorageManager mStorageManager; + private static class MoveInfo { + public int moveId; + public Bundle extras; + public String packageName; + public String label; + public String volumeUuid; + } + + private final SparseArray<MoveInfo> mMoves = new SparseArray<>(); + private final StorageEventListener mListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { - onVolumeStateChangedInternal(vol, oldState, newState); + onVolumeStateChangedInternal(vol); } @Override - public void onVolumeMetadataChanged(VolumeInfo vol) { + public void onVolumeRecordChanged(VolumeRecord rec) { // Avoid kicking notifications when getting early metadata before // mounted. If already mounted, we're being kicked because of a // nickname or init'ed change. - if (vol.isMountedReadable()) { - onVolumeStateChangedInternal(vol, vol.getState(), vol.getState()); + final VolumeInfo vol = mStorageManager.findVolumeByUuid(rec.getFsUuid()); + if (vol != null && vol.isMountedReadable()) { + onVolumeStateChangedInternal(vol); } } + + @Override + public void onVolumeForgotten(String fsUuid) { + // Stop annoying the user + mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL); + } + + @Override + public void onDiskScanned(DiskInfo disk, int volumeCount) { + onDiskScannedInternal(disk, volumeCount); + } }; private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO: kick this onto background thread - final String volId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID); - mStorageManager.setVolumeSnoozed(volId, true); + final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID); + mStorageManager.setVolumeSnoozed(fsUuid, true); + } + }; + + private final MoveCallback mMoveCallback = new MoveCallback() { + @Override + public void onCreated(int moveId, Bundle extras) { + final MoveInfo move = new MoveInfo(); + move.moveId = moveId; + move.extras = extras; + if (extras != null) { + move.packageName = extras.getString(Intent.EXTRA_PACKAGE_NAME); + move.label = extras.getString(Intent.EXTRA_TITLE); + move.volumeUuid = extras.getString(VolumeRecord.EXTRA_FS_UUID); + } + mMoves.put(moveId, move); + } + + @Override + public void onStatusChanged(int moveId, int status, long estMillis) { + final MoveInfo move = mMoves.get(moveId); + if (move == null) { + Log.w(TAG, "Ignoring unknown move " + moveId); + return; + } + + if (PackageManager.isMoveStatusFinished(status)) { + onMoveFinished(move, status); + } else { + onMoveProgress(move, status, estMillis); + } } }; @@ -88,20 +150,99 @@ public class StorageNotification extends SystemUI { // Kick current state into place final List<VolumeInfo> vols = mStorageManager.getVolumes(); for (VolumeInfo vol : vols) { - onVolumeStateChangedInternal(vol, vol.getState(), vol.getState()); + onVolumeStateChangedInternal(vol); } + + mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler()); + + updateMissingPrivateVolumes(); } - public void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) { - // We only care about public volumes - if (vol.getType() != VolumeInfo.TYPE_PUBLIC) { - return; + private void updateMissingPrivateVolumes() { + final List<VolumeRecord> recs = mStorageManager.getVolumeRecords(); + for (VolumeRecord rec : recs) { + if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue; + + final String fsUuid = rec.getFsUuid(); + final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid); + if (info != null && info.isMountedWritable()) { + // Yay, private volume is here! + mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL); + + } else { + // Boo, annoy the user to reinsert the private volume + final CharSequence title = mContext.getString(R.string.ext_media_missing_title, + rec.getNickname()); + final CharSequence text = mContext.getString(R.string.ext_media_missing_message); + + final Notification notif = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_notify_sdcard) + .setColor(mContext.getColor(R.color.system_notification_accent_color)) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(buildForgetPendingIntent(rec)) + .setStyle(new Notification.BigTextStyle().bigText(text)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_SYSTEM) + .setOngoing(true) + .build(); + + mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL); + } } + } + + private void onDiskScannedInternal(DiskInfo disk, int volumeCount) { + if (volumeCount == 0) { + // No supported volumes found, give user option to format + final CharSequence title = mContext.getString( + R.string.ext_media_unmountable_notification_title, disk.getDescription()); + final CharSequence text = mContext.getString( + R.string.ext_media_unmountable_notification_message, disk.getDescription()); + + final Notification notif = new Notification.Builder(mContext) + .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE)) + .setColor(mContext.getColor(R.color.system_notification_accent_color)) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(buildInitPendingIntent(disk)) + .setStyle(new Notification.BigTextStyle().bigText(text)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_ERROR) + .build(); - Log.d(TAG, vol.toString()); + mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL); + + } else { + // Yay, we have volumes! + mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL); + } + } + + private void onVolumeStateChangedInternal(VolumeInfo vol) { + switch (vol.getType()) { + case VolumeInfo.TYPE_PRIVATE: + onPrivateVolumeStateChangedInternal(vol); + break; + case VolumeInfo.TYPE_PUBLIC: + onPublicVolumeStateChangedInternal(vol); + break; + } + } + + private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) { + Log.d(TAG, "Notifying about private volume: " + vol.toString()); + + updateMissingPrivateVolumes(); + } + + private void onPublicVolumeStateChangedInternal(VolumeInfo vol) { + Log.d(TAG, "Notifying about public volume: " + vol.toString()); final Notification notif; - switch (newState) { + switch (vol.getState()) { case VolumeInfo.STATE_UNMOUNTED: notif = onVolumeUnmounted(vol); break; @@ -133,9 +274,9 @@ public class StorageNotification extends SystemUI { } if (notif != null) { - mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL); + mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL); } else { - mNotificationManager.cancelAsUser(vol.getId(), NOTIF_ID, UserHandle.ALL); + mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL); } } @@ -159,20 +300,24 @@ public class StorageNotification extends SystemUI { } private Notification onVolumeMounted(VolumeInfo vol) { + final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid()); + // Don't annoy when user dismissed in past - if (vol.isSnoozed()) return null; + if (rec.isSnoozed()) return null; final DiskInfo disk = vol.getDisk(); - if (disk.isAdoptable() && !vol.isInited()) { + if (disk.isAdoptable() && !rec.isInited()) { final CharSequence title = disk.getDescription(); final CharSequence text = mContext.getString( R.string.ext_media_new_notification_message, disk.getDescription()); + final PendingIntent initIntent = buildInitPendingIntent(vol); return buildNotificationBuilder(vol, title, text) .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action), - buildInitPendingIntent(vol))) + initIntent)) .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action), buildUnmountPendingIntent(vol))) + .setContentIntent(initIntent) .setDeleteIntent(buildSnoozeIntent(vol)) .setCategory(Notification.CATEGORY_SYSTEM) .build(); @@ -182,11 +327,13 @@ public class StorageNotification extends SystemUI { final CharSequence text = mContext.getString( R.string.ext_media_ready_notification_message, disk.getDescription()); + final PendingIntent browseIntent = buildBrowsePendingIntent(vol); return buildNotificationBuilder(vol, title, text) .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action), - buildBrowsePendingIntent(vol))) + browseIntent)) .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action), buildUnmountPendingIntent(vol))) + .setContentIntent(browseIntent) .setDeleteIntent(buildSnoozeIntent(vol)) .setCategory(Notification.CATEGORY_SYSTEM) .setPriority(Notification.PRIORITY_LOW) @@ -221,7 +368,7 @@ public class StorageNotification extends SystemUI { R.string.ext_media_unmountable_notification_message, disk.getDescription()); return buildNotificationBuilder(vol, title, text) - .setContentIntent(buildDetailsPendingIntent(vol)) + .setContentIntent(buildVolumeSettingsPendingIntent(vol)) .setCategory(Notification.CATEGORY_ERROR) .build(); } @@ -260,16 +407,102 @@ public class StorageNotification extends SystemUI { .build(); } - private int getSmallIcon(VolumeInfo vol) { - if (vol.disk.isSd()) { - switch (vol.getState()) { + private void onMoveProgress(MoveInfo move, int status, long estMillis) { + final CharSequence title; + if (!TextUtils.isEmpty(move.label)) { + title = mContext.getString(R.string.ext_media_move_specific_title, move.label); + } else { + title = mContext.getString(R.string.ext_media_move_title); + } + + final CharSequence text; + if (estMillis < 0) { + text = null; + } else { + text = DateUtils.formatDuration(estMillis); + } + + final PendingIntent intent; + if (move.packageName != null) { + intent = buildWizardMovePendingIntent(move); + } else { + intent = buildWizardMigratePendingIntent(move); + } + + final Notification notif = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_notify_sdcard) + .setColor(mContext.getColor(R.color.system_notification_accent_color)) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(intent) + .setStyle(new Notification.BigTextStyle().bigText(text)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_PROGRESS) + .setPriority(Notification.PRIORITY_LOW) + .setProgress(100, status, false) + .setOngoing(true) + .build(); + + mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL); + } + + private void onMoveFinished(MoveInfo move, int status) { + if (move.packageName != null) { + // We currently ignore finished app moves; just clear the last + // published progress + mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL); + return; + } + + final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume(); + final String descrip = mStorageManager.getBestVolumeDescription(privateVol); + + final CharSequence title; + final CharSequence text; + if (status == PackageManager.MOVE_SUCCEEDED) { + title = mContext.getString(R.string.ext_media_move_success_title); + text = mContext.getString(R.string.ext_media_move_success_message, descrip); + } else { + title = mContext.getString(R.string.ext_media_move_failure_title); + text = mContext.getString(R.string.ext_media_move_failure_message); + } + + // Jump back into the wizard flow if we moved to a real disk + final PendingIntent intent; + if (privateVol != null && privateVol.getDisk() != null) { + intent = buildWizardReadyPendingIntent(privateVol.getDisk()); + } else { + intent = buildVolumeSettingsPendingIntent(privateVol); + } + + final Notification notif = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_notify_sdcard) + .setColor(mContext.getColor(R.color.system_notification_accent_color)) + .setContentTitle(title) + .setContentText(text) + .setContentIntent(intent) + .setStyle(new Notification.BigTextStyle().bigText(text)) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_SYSTEM) + .setPriority(Notification.PRIORITY_LOW) + .setAutoCancel(true) + .build(); + + mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL); + } + + private int getSmallIcon(DiskInfo disk, int state) { + if (disk.isSd()) { + switch (state) { case VolumeInfo.STATE_CHECKING: case VolumeInfo.STATE_EJECTING: return R.drawable.stat_notify_sdcard_prepare; default: return R.drawable.stat_notify_sdcard; } - } else if (vol.disk.isUsb()) { + } else if (disk.isUsb()) { return R.drawable.stat_sys_data_usb; } else { return R.drawable.stat_notify_sdcard; @@ -279,7 +512,7 @@ public class StorageNotification extends SystemUI { private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title, CharSequence text) { return new Notification.Builder(mContext) - .setSmallIcon(getSmallIcon(vol)) + .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState())) .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setContentTitle(title) .setContentText(text) @@ -288,6 +521,17 @@ public class StorageNotification extends SystemUI { .setLocalOnly(true); } + private PendingIntent buildInitPendingIntent(DiskInfo disk) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardInit"); + intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId()); + + final int requestKey = disk.getId().hashCode(); + return PendingIntent.getActivityAsUser(mContext, requestKey, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + private PendingIntent buildInitPendingIntent(VolumeInfo vol) { final Intent intent = new Intent(); intent.setClassName("com.android.settings", @@ -318,10 +562,20 @@ public class StorageNotification extends SystemUI { PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); } - private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) { + private PendingIntent buildVolumeSettingsPendingIntent(VolumeInfo vol) { final Intent intent = new Intent(); - intent.setClassName("com.android.settings", - "com.android.settings.Settings$StorageVolumeSettingsActivity"); + switch (vol.getType()) { + case VolumeInfo.TYPE_PRIVATE: + intent.setClassName("com.android.settings", + "com.android.settings.Settings$PrivateVolumeSettingsActivity"); + break; + case VolumeInfo.TYPE_PUBLIC: + intent.setClassName("com.android.settings", + "com.android.settings.Settings$PublicVolumeSettingsActivity"); + break; + default: + return null; + } intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); final int requestKey = vol.getId().hashCode(); @@ -331,10 +585,55 @@ public class StorageNotification extends SystemUI { private PendingIntent buildSnoozeIntent(VolumeInfo vol) { final Intent intent = new Intent(ACTION_SNOOZE_VOLUME); - intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); + intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid()); final int requestKey = vol.getId().hashCode(); return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent, PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT); } + + private PendingIntent buildForgetPendingIntent(VolumeRecord rec) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.Settings$PrivateVolumeForgetActivity"); + intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid()); + + final int requestKey = rec.getFsUuid().hashCode(); + return PendingIntent.getActivityAsUser(mContext, requestKey, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + + private PendingIntent buildWizardMigratePendingIntent(MoveInfo move) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardMigrateProgress"); + intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId); + + final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid); + intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); + + return PendingIntent.getActivityAsUser(mContext, move.moveId, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + + private PendingIntent buildWizardMovePendingIntent(MoveInfo move) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardMoveProgress"); + intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId); + + return PendingIntent.getActivityAsUser(mContext, move.moveId, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } + + private PendingIntent buildWizardReadyPendingIntent(DiskInfo disk) { + final Intent intent = new Intent(); + intent.setClassName("com.android.settings", + "com.android.settings.deviceinfo.StorageWizardReady"); + intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId()); + + final int requestKey = disk.getId().hashCode(); + return PendingIntent.getActivityAsUser(mContext, requestKey, intent, + PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java index 4f20ac7..f7cb9fe 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java +++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java @@ -17,6 +17,7 @@ package com.android.systemui.volume; import android.content.Context; +import android.graphics.Typeface; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -30,6 +31,8 @@ import java.util.Objects; public class SegmentedButtons extends LinearLayout { private static final int LABEL_RES_KEY = R.id.label; + private static final Typeface REGULAR = Typeface.create("sans-serif", Typeface.NORMAL); + private static final Typeface MEDIUM = Typeface.create("sans-serif-medium", Typeface.NORMAL); private final Context mContext; private final LayoutInflater mInflater; @@ -60,6 +63,7 @@ public class SegmentedButtons extends LinearLayout { final Object tag = c.getTag(); final boolean selected = Objects.equals(mSelectedValue, tag); c.setSelected(selected); + c.setTypeface(selected ? MEDIUM : REGULAR); } fireOnSelected(); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java index 216a4da..4214091 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Util.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java @@ -144,9 +144,14 @@ class Util { return HMMAA.format(new Date(millis)); } - public static void setText(TextView tv, CharSequence text) { - if (Objects.equals(tv.getText(), text)) return; + private static CharSequence emptyToNull(CharSequence str) { + return str == null || str.length() == 0 ? null : str; + } + + public static boolean setText(TextView tv, CharSequence text) { + if (Objects.equals(emptyToNull(tv.getText()), emptyToNull(text))) return false; tv.setText(text); + return true; } public static final void setVisOrGone(View v, boolean vis) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index bb4aa61..9434036 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -37,7 +37,6 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.provider.Settings.Global; -import android.service.notification.ZenModeConfig; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseBooleanArray; @@ -52,7 +51,6 @@ import android.view.ViewGroup.MarginLayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; -import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.SeekBar; @@ -90,16 +88,12 @@ public class VolumeDialog { private final ViewGroup mDialogView; private final ViewGroup mDialogContentView; private final ImageButton mExpandButton; - private final TextView mFootlineText; - private final Button mFootlineAction; private final View mSettingsButton; - private final View mFooter; private final List<VolumeRow> mRows = new ArrayList<VolumeRow>(); private final SpTexts mSpTexts; private final SparseBooleanArray mDynamic = new SparseBooleanArray(); private final KeyguardManager mKeyguard; private final int mExpandButtonAnimationDuration; - private final View mTextFooter; private final ZenFooter mZenFooter; private final LayoutTransition mLayoutTransition; private final Object mSafetyWarningLock = new Object(); @@ -108,8 +102,6 @@ public class VolumeDialog { private boolean mExpanded; private int mActiveStream; private boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS; - private boolean mShowFooter = VolumePrefs.DEFAULT_SHOW_FOOTER; - private boolean mShowZenFooter = VolumePrefs.DEFAULT_ZEN_FOOTER; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE; private State mState; @@ -118,7 +110,7 @@ public class VolumeDialog { private SafetyWarningDialog mSafetyWarning; private Callback mCallback; - public VolumeDialog(Context context, VolumeDialogController controller, + public VolumeDialog(Context context, int windowType, VolumeDialogController controller, ZenModeController zenModeController, Callback callback) { mContext = context; mController = controller; @@ -141,7 +133,7 @@ public class VolumeDialog { mDialog.setCanceledOnTouchOutside(true); final Resources res = mContext.getResources(); final WindowManager.LayoutParams lp = window.getAttributes(); - lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; + lp.type = windowType; lp.format = PixelFormat.TRANSLUCENT; lp.setTitle(VolumeDialog.class.getSimpleName()); lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; @@ -176,17 +168,11 @@ public class VolumeDialog { addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false); - mTextFooter = mDialog.findViewById(R.id.volume_text_footer); - mFootlineText = (TextView) mDialog.findViewById(R.id.volume_footline_text); - mSpTexts.add(mFootlineText); - mFootlineAction = (Button) mDialog.findViewById(R.id.volume_footline_action_button); - mSpTexts.add(mFootlineAction); - mFooter = mDialog.findViewById(R.id.volume_footer); mSettingsButton = mDialog.findViewById(R.id.volume_settings_button); mSettingsButton.setOnClickListener(mClickSettings); mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration); mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer); - mZenFooter.init(zenModeController, mZenFooterCallback); + mZenFooter.init(zenModeController); controller.addCallback(mControllerCallbackH, mHandler); controller.getState(); @@ -217,18 +203,6 @@ public class VolumeDialog { mHandler.sendEmptyMessage(H.RECHECK_ALL); } - public void setShowFooter(boolean show) { - if (mShowFooter == show) return; - mShowFooter = show; - mHandler.sendEmptyMessage(H.RECHECK_ALL); - } - - public void setZenFooter(boolean zen) { - if (mShowZenFooter == zen) return; - mShowZenFooter = zen; - mHandler.sendEmptyMessage(H.RECHECK_ALL); - } - public void setAutomute(boolean automute) { if (mAutomute == automute) return; mAutomute = automute; @@ -315,7 +289,6 @@ public class VolumeDialog { writer.print(" mActiveStream: "); writer.println(mActiveStream); writer.print(" mDynamic: "); writer.println(mDynamic); writer.print(" mShowHeaders: "); writer.println(mShowHeaders); - writer.print(" mShowFooter: "); writer.println(mShowFooter); writer.print(" mAutomute: "); writer.println(mAutomute); writer.print(" mSilentMode: "); writer.println(mSilentMode); } @@ -444,7 +417,6 @@ public class VolumeDialog { } private int computeTimeoutH() { - if (mZenFooter != null && mZenFooter.isFooterExpanded()) return 10000; if (mSafetyWarning != null) return 5000; if (mExpanded || mExpanding) return 5000; if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500; @@ -515,18 +487,9 @@ public class VolumeDialog { final VolumeRow activeRow = getActiveRow(); updateFooterH(); updateExpandButtonH(); - final boolean footerVisible = mFooter.getVisibility() == View.VISIBLE; if (!mShowing) { trimObsoleteH(); } - // first, find the last visible row - VolumeRow lastVisible = null; - for (VolumeRow row : mRows) { - final boolean isActive = row == activeRow; - if (isVisibleH(row, isActive)) { - lastVisible = row; - } - } // apply changes to all rows for (VolumeRow row : mRows) { final boolean isActive = row == activeRow; @@ -542,8 +505,7 @@ public class VolumeDialog { row.settingsButton.setImageResource(expandButtonRes); } } - Util.setVisOrInvis(row.settingsButton, - mExpanded && (!footerVisible && row == lastVisible)); + Util.setVisOrInvis(row.settingsButton, false); row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f); } } @@ -585,51 +547,9 @@ public class VolumeDialog { updateFooterH(); } - private void updateTextFooterH() { - final boolean zen = mState.zenMode != Global.ZEN_MODE_OFF; - final boolean wasVisible = mFooter.getVisibility() == View.VISIBLE; - Util.setVisOrGone(mTextFooter, mExpanded && mShowFooter && (zen || mShowing && wasVisible)); - if (mTextFooter.getVisibility() == View.VISIBLE) { - String text = null; - String action = null; - if (mState.exitCondition != null) { - final long countdown = ZenModeConfig.tryParseCountdownConditionId(mState - .exitCondition.id); - if (countdown != 0) { - text = mContext.getString(R.string.volume_dnd_ends_at, - Util.getShortTime(countdown)); - action = mContext.getString(R.string.volume_end_now); - } - } - if (text == null) { - text = mContext.getString(R.string.volume_dnd_is_on); - } - if (action == null) { - action = mContext.getString(R.string.volume_turn_off); - } - Util.setText(mFootlineText, text); - Util.setText(mFootlineAction, action); - mFootlineAction.setOnClickListener(mTurnOffDnd); - } - Util.setVisOrGone(mFootlineText, zen); - Util.setVisOrGone(mFootlineAction, zen); - } - private void updateFooterH() { - if (!mShowFooter) { - Util.setVisOrGone(mFooter, false); - return; - } - if (mShowZenFooter) { - Util.setVisOrGone(mTextFooter, false); - final boolean ringActive = mActiveStream == AudioManager.STREAM_RING; - Util.setVisOrGone(mZenFooter, mZenFooter.isZen() && ringActive - || mShowing && (mExpanded || mZenFooter.getVisibility() == View.VISIBLE)); - mZenFooter.update(); - } else { - Util.setVisOrGone(mZenFooter, false); - updateTextFooterH(); - } + Util.setVisOrGone(mZenFooter, mState.zenMode != Global.ZEN_MODE_OFF); + mZenFooter.update(); } private void updateVolumeRowH(VolumeRow row) { @@ -642,12 +562,20 @@ public class VolumeDialog { } final boolean isRingStream = row.stream == AudioManager.STREAM_RING; final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM; + final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM; + final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC; final boolean isRingVibrate = isRingStream && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE; - final boolean isNoned = (isRingStream || isSystemStream) - && mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - final boolean isLimited = isRingStream - && mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + final boolean isRingSilent = isRingStream + && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT; + final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS; + final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; + final boolean isZenPriority = mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + final boolean isRingZenNone = (isRingStream || isSystemStream) && isZenNone; + final boolean isRingLimited = isRingStream && isZenPriority; + final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream) + : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream) + : false; // update slider max final int max = ss.levelMax * 100; @@ -663,15 +591,15 @@ public class VolumeDialog { // update header text final String text; - if (isNoned) { + if (isRingZenNone) { text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name); - } else if (isRingVibrate && isLimited) { + } else if (isRingVibrate && isRingLimited) { text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name); } else if (isRingVibrate) { text = mContext.getString(R.string.volume_stream_vibrate, ss.name); } else if (ss.muted || mAutomute && ss.level == 0) { text = mContext.getString(R.string.volume_stream_muted, ss.name); - } else if (isLimited) { + } else if (isRingLimited) { text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name); } else { text = ss.name; @@ -679,11 +607,12 @@ public class VolumeDialog { Util.setText(row.header, text); // update icon - final boolean iconEnabled = mAutomute || ss.muteSupported; + final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; row.icon.setEnabled(iconEnabled); row.icon.setAlpha(iconEnabled ? 1 : 0.5f); final int iconRes = isRingVibrate ? R.drawable.ic_volume_ringer_vibrate + : isRingSilent || zenMuted ? row.cachedIconRes : ss.routedToBluetooth ? (ss.muted ? R.drawable.ic_volume_media_bt_mute : R.drawable.ic_volume_media_bt) @@ -705,10 +634,11 @@ public class VolumeDialog { : Events.ICON_STATE_UNKNOWN; // update slider - updateVolumeRowSliderH(row); + updateVolumeRowSliderH(row, zenMuted); } - private void updateVolumeRowSliderH(VolumeRow row) { + private void updateVolumeRowSliderH(VolumeRow row, boolean zenMuted) { + row.slider.setEnabled(!zenMuted); if (row.tracking) { return; // don't update if user is sliding } @@ -887,46 +817,6 @@ public class VolumeDialog { } }; - private final View.OnClickListener mTurnOffDnd = new View.OnClickListener() { - @Override - public void onClick(View v) { - mSettingsButton.postDelayed(new Runnable() { - @Override - public void run() { - mController.setZenMode(Global.ZEN_MODE_OFF); - } - }, WAIT_FOR_RIPPLE); - } - }; - - private final ZenFooter.Callback mZenFooterCallback = new ZenFooter.Callback() { - @Override - public void onFooterExpanded() { - mHandler.sendEmptyMessage(H.RESCHEDULE_TIMEOUT); - } - - @Override - public void onSettingsClicked() { - dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED); - if (mCallback != null) { - mCallback.onZenSettingsClicked(); - } - } - - @Override - public void onDoneClicked() { - dismiss(Events.DISMISS_REASON_DONE_CLICKED); - } - - @Override - public void onPrioritySettingsClicked() { - dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED); - if (mCallback != null) { - mCallback.onZenPrioritySettingsClicked(); - } - } - }; - private final class H extends Handler { private static final int SHOW = 1; private static final int DISMISS = 2; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java index 86abfcc..1083f40 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java @@ -24,6 +24,7 @@ import android.media.VolumePolicy; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; +import android.view.WindowManager; import com.android.systemui.SystemUI; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -61,7 +62,8 @@ public class VolumeDialogComponent implements VolumeComponent { } }; mZenModeController = zen; - mDialog = new VolumeDialog(context, mController, zen, mVolumeDialogCallback); + mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY, + mController, zen, mVolumeDialogCallback); applyConfiguration(); } @@ -76,12 +78,10 @@ public class VolumeDialogComponent implements VolumeComponent { mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true); mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false); mDialog.setShowHeaders(false); - mDialog.setShowFooter(true); - mDialog.setZenFooter(true); mDialog.setAutomute(true); mDialog.setSilentMode(false); mController.setVolumePolicy(mVolumePolicy); - mController.showDndTile(false); + mController.showDndTile(true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java index 012eb41..3a8081f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java @@ -100,7 +100,7 @@ public class VolumeDialogController { private boolean mEnabled; private boolean mDestroyed; private VolumePolicy mVolumePolicy; - private boolean mShowDndTile = false; + private boolean mShowDndTile = true; public VolumeDialogController(Context context, ComponentName component) { mContext = context.getApplicationContext(); @@ -125,6 +125,10 @@ public class VolumeDialogController { return mAudio; } + public ZenModeConfig getZenModeConfig() { + return mNoMan.getZenModeConfig(); + } + public void dismiss() { mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER); } @@ -342,7 +346,7 @@ public class VolumeDialogController { updateRingerModeExternalW(mAudio.getRingerMode()); updateZenModeW(); updateEffectsSuppressorW(mNoMan.getEffectsSuppressor()); - updateExitConditionW(); + updateZenModeConfigW(); mCallbacks.onStateChanged(mState); } @@ -395,17 +399,10 @@ public class VolumeDialogController { return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION; } - private Condition getExitCondition() { - final ZenModeConfig config = mNoMan.getZenModeConfig(); - return config == null ? null - : config.manualRule == null ? null - : config.manualRule.condition; - } - - private boolean updateExitConditionW() { - final Condition exitCondition = getExitCondition(); - if (Objects.equals(mState.exitCondition, exitCondition)) return false; - mState.exitCondition = exitCondition; + private boolean updateZenModeConfigW() { + final ZenModeConfig zenModeConfig = getZenModeConfig(); + if (Objects.equals(mState.zenModeConfig, zenModeConfig)) return false; + mState.zenModeConfig = zenModeConfig; return true; } @@ -750,7 +747,7 @@ public class VolumeDialogController { changed = updateZenModeW(); } if (ZEN_MODE_CONFIG_URI.equals(uri)) { - changed = updateExitConditionW(); + changed = updateZenModeConfigW(); } if (changed) { mCallbacks.onStateChanged(mState); @@ -943,7 +940,7 @@ public class VolumeDialogController { public int zenMode; public ComponentName effectsSuppressor; public String effectsSuppressorName; - public Condition exitCondition; + public ZenModeConfig zenModeConfig; public int activeStream = NO_ACTIVE_STREAM; public State copy() { @@ -956,7 +953,7 @@ public class VolumeDialogController { rt.zenMode = zenMode; if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone(); rt.effectsSuppressorName = effectsSuppressorName; - if (exitCondition != null) rt.exitCondition = exitCondition.copy(); + if (zenModeConfig != null) rt.zenModeConfig = zenModeConfig.copy(); rt.activeStream = activeStream; return rt; } @@ -977,10 +974,15 @@ public class VolumeDialogController { sb.append(",zenMode:").append(zenMode); sb.append(",effectsSuppressor:").append(effectsSuppressor); sb.append(",effectsSuppressorName:").append(effectsSuppressorName); - sb.append(",exitCondition:").append(exitCondition); + sb.append(",zenModeConfig:").append(zenModeConfig); sb.append(",activeStream:").append(activeStream); return sb.append('}').toString(); } + + public Condition getManualExitCondition() { + return zenModeConfig != null && zenModeConfig.manualRule != null + ? zenModeConfig.manualRule.condition : null; + } } public interface Callbacks { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java index 915e998..04339eb 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java @@ -32,8 +32,6 @@ public class VolumePrefs { public static final String PREF_SHOW_HEADERS = "pref_show_headers"; public static final String PREF_SHOW_FAKE_REMOTE_1 = "pref_show_fake_remote_1"; public static final String PREF_SHOW_FAKE_REMOTE_2 = "pref_show_fake_remote_2"; - public static final String PREF_SHOW_FOOTER = "pref_show_footer"; - public static final String PREF_ZEN_FOOTER = "pref_zen_footer"; public static final String PREF_ENABLE_AUTOMUTE = "pref_enable_automute"; public static final String PREF_ENABLE_SILENT_MODE = "pref_enable_silent_mode"; public static final String PREF_DEBUG_LOGGING = "pref_debug_logging"; @@ -46,10 +44,8 @@ public class VolumePrefs { public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification"; public static final boolean DEFAULT_SHOW_HEADERS = true; - public static final boolean DEFAULT_SHOW_FOOTER = true; public static final boolean DEFAULT_ENABLE_AUTOMUTE = true; public static final boolean DEFAULT_ENABLE_SILENT_MODE = true; - public static final boolean DEFAULT_ZEN_FOOTER = true; public static void unregisterCallbacks(Context c, OnSharedPreferenceChangeListener listener) { prefs(c).unregisterOnSharedPreferenceChangeListener(listener); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index 5f04aaf..2688813 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -103,7 +103,7 @@ public class VolumeUI extends SystemUI { private void setDefaultVolumeController(boolean register) { if (register) { - DndTile.setVisible(mContext, false); + DndTile.setVisible(mContext, true); if (LOGD) Log.d(TAG, "Registering default volume controller"); getVolumeComponent().register(); } else { diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java index 775c87d..8aded45 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java @@ -16,20 +16,12 @@ package com.android.systemui.volume; import android.animation.LayoutTransition; -import android.animation.ValueAnimator; -import android.app.ActivityManager; import android.content.Context; -import android.content.res.Resources; import android.provider.Settings.Global; import android.service.notification.ZenModeConfig; import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; import android.view.View; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.LinearLayout; -import android.widget.Switch; import android.widget.TextView; import com.android.systemui.R; @@ -38,70 +30,36 @@ import com.android.systemui.statusbar.policy.ZenModeController; import java.util.Objects; /** - * Switch bar + zen mode panel (conditions) attached to the bottom of the volume dialog. + * Zen mode information (and end button) attached to the bottom of the volume dialog. */ public class ZenFooter extends LinearLayout { private static final String TAG = Util.logTag(ZenFooter.class); private final Context mContext; - private final float mSecondaryAlpha; - private final LayoutTransition mLayoutTransition; - private ZenModeController mController; - private Switch mSwitch; - private ZenModePanel mZenModePanel; - private View mZenModePanelButtons; - private View mZenModePanelMoreButton; - private View mZenModePanelDoneButton; - private View mSwitchBar; - private View mSwitchBarIcon; - private View mSummary; private TextView mSummaryLine1; private TextView mSummaryLine2; - private boolean mFooterExpanded; + private View mEndNowButton; private int mZen = -1; private ZenModeConfig mConfig; - private Callback mCallback; + private ZenModeController mController; public ZenFooter(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; - mSecondaryAlpha = getFloat(context.getResources(), R.dimen.volume_secondary_alpha); - mLayoutTransition = new LayoutTransition(); - mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2); - mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING); - mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - } - - private static float getFloat(Resources r, int resId) { - final TypedValue tv = new TypedValue(); - r.getValue(resId, tv, true); - return tv.getFloat(); + setLayoutTransition(new LayoutTransition()); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mSwitchBar = findViewById(R.id.volume_zen_switch_bar); - mSwitchBarIcon = findViewById(R.id.volume_zen_switch_bar_icon); - mSwitch = (Switch) findViewById(R.id.volume_zen_switch); - mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel); - mZenModePanelButtons = findViewById(R.id.volume_zen_mode_panel_buttons); - mZenModePanelMoreButton = findViewById(R.id.volume_zen_mode_panel_more); - mZenModePanelDoneButton = findViewById(R.id.volume_zen_mode_panel_done); - mSummary = findViewById(R.id.volume_zen_panel_summary); - mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_1); - mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_2); + mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_summary_line_1); + mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_summary_line_2); + mEndNowButton = findViewById(R.id.volume_zen_end_now); } - public void init(ZenModeController controller, Callback callback) { - mCallback = callback; - mController = controller; - mZenModePanel.init(controller); - mZenModePanel.setEmbedded(true); - mZenModePanel.setCallback(mZenModePanelCallback); - mSwitch.setOnCheckedChangeListener(mCheckedListener); - mController.addCallback(new ZenModeController.Callback() { + public void init(final ZenModeController controller) { + controller.addCallback(new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { setZen(zen); @@ -111,30 +69,15 @@ public class ZenFooter extends LinearLayout { setConfig(config); } }); - mSwitchBar.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mSwitch.setChecked(!mSwitch.isChecked()); - } - }); - mZenModePanelMoreButton.setOnClickListener(new OnClickListener() { + mEndNowButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - if (mCallback != null) { - mCallback.onSettingsClicked(); - } + controller.setZen(Global.ZEN_MODE_OFF, null, TAG); } }); - mZenModePanelDoneButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mCallback != null) { - mCallback.onDoneClicked(); - } - } - }); - mZen = mController.getZen(); - mConfig = mController.getConfig(); + mZen = controller.getZen(); + mConfig = controller.getConfig(); + mController = controller; update(); } @@ -166,96 +109,17 @@ public class ZenFooter extends LinearLayout { return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS; } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - setLayoutTransition(null); - setFooterExpanded(false); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - setLayoutTransition(mLayoutTransition); - } - - private boolean setFooterExpanded(boolean expanded) { - if (mFooterExpanded == expanded) return false; - mFooterExpanded = expanded; - update(); - if (mCallback != null) { - mCallback.onFooterExpanded(); - } - return true; - } - - public boolean isFooterExpanded() { - return mFooterExpanded; - } - public void update() { - final boolean isZen = isZen(); - mSwitch.setOnCheckedChangeListener(null); - mSwitch.setChecked(isZen); - mSwitch.setOnCheckedChangeListener(mCheckedListener); - Util.setVisOrGone(mZenModePanel, isZen && mFooterExpanded); - Util.setVisOrGone(mZenModePanelButtons, isZen && mFooterExpanded); - Util.setVisOrGone(mSummary, isZen && !mFooterExpanded); - mSwitchBarIcon.setAlpha(isZen ? 1 : mSecondaryAlpha); final String line1 = isZenPriority() ? mContext.getString(R.string.interruption_level_priority) : isZenAlarms() ? mContext.getString(R.string.interruption_level_alarms) : isZenNone() ? mContext.getString(R.string.interruption_level_none) : null; Util.setText(mSummaryLine1, line1); + final String line2 = ZenModeConfig.getConditionSummary(mContext, mConfig, - ActivityManager.getCurrentUser()); + mController.getCurrentUser()); Util.setText(mSummaryLine2, line2); } - private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() { - @Override - public void onMoreSettings() { - if (mCallback != null) { - mCallback.onSettingsClicked(); - } - } - - @Override - public void onPrioritySettings() { - if (mCallback != null) { - mCallback.onPrioritySettingsClicked(); - } - } - - @Override - public void onInteraction() { - // noop - } - - @Override - public void onExpanded(boolean expanded) { - // noop - } - }; - - private final OnCheckedChangeListener mCheckedListener = new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (D.BUG) Log.d(TAG, "onCheckedChanged " + isChecked); - if (isChecked != isZen()) { - final int newZen = isChecked ? Global.ZEN_MODE_ALARMS : Global.ZEN_MODE_OFF; - mZen = newZen; // this one's optimistic - setFooterExpanded(isChecked); - mController.setZen(newZen, null, TAG); - } - } - }; - - public interface Callback { - void onFooterExpanded(); - void onSettingsClicked(); - void onDoneClicked(); - void onPrioritySettingsClicked(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 1b563dc..9f9c9ac 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -41,8 +41,6 @@ import android.util.MathUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; @@ -85,22 +83,14 @@ public class ZenModePanel extends LinearLayout { private final H mHandler = new H(); private final ZenPrefs mPrefs; private final IconPulser mIconPulser; - private final int mSubheadWarningColor; - private final int mSubheadColor; - private final Interpolator mInterpolator; private final TransitionHelper mTransitionHelper = new TransitionHelper(); private final Uri mForeverId; private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this)); private SegmentedButtons mZenButtons; - private ViewGroup mZenButtonsContainer; - private View mZenSubhead; - private TextView mZenSubheadCollapsed; - private TextView mZenSubheadExpanded; - private View mZenEmbeddedDivider; - private View mMoreSettings; private View mZenIntroduction; + private TextView mZenIntroductionMessage; private View mZenIntroductionConfirm; private View mZenIntroductionCustomize; private LinearLayout mZenConditions; @@ -113,7 +103,6 @@ public class ZenModePanel extends LinearLayout { private int mFirstConditionIndex; private boolean mRequestingConditions; private Condition mExitCondition; - private String mExitConditionText; private int mBucketIndex = -1; private boolean mExpanded; private boolean mHidden; @@ -123,7 +112,6 @@ public class ZenModePanel extends LinearLayout { private Condition mSessionExitCondition; private Condition[] mConditions; private Condition mTimeCondition; - private boolean mEmbedded; public ZenModePanel(Context context, AttributeSet attrs) { super(context, attrs); @@ -131,10 +119,6 @@ public class ZenModePanel extends LinearLayout { mPrefs = new ZenPrefs(); mInflater = LayoutInflater.from(mContext.getApplicationContext()); mIconPulser = new IconPulser(mContext); - mSubheadWarningColor = context.getColor(R.color.system_warning_color); - mSubheadColor = context.getColor(R.color.qs_subhead); - mInterpolator = AnimationUtils.loadInterpolator(mContext, - com.android.internal.R.interpolator.fast_out_slow_in); mForeverId = Condition.newId(mContext).appendPath("forever").build(); if (DEBUG) Log.d(mTag, "new ZenModePanel"); } @@ -149,25 +133,13 @@ public class ZenModePanel extends LinearLayout { pw.print(" mExpanded="); pw.println(mExpanded); pw.print(" mSessionZen="); pw.println(mSessionZen); pw.print(" mAttachedZen="); pw.println(mAttachedZen); - pw.print(" mEmbedded="); pw.println(mEmbedded); + pw.print(" mConfirmedPriorityIntroduction="); + pw.println(mPrefs.mConfirmedPriorityIntroduction); + pw.print(" mConfirmedSilenceIntroduction="); + pw.println(mPrefs.mConfirmedSilenceIntroduction); mTransitionHelper.dump(fd, pw, args); } - public void setEmbedded(boolean embedded) { - if (mEmbedded == embedded) return; - mEmbedded = embedded; - mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null)); - setLayoutTransition(mEmbedded ? null : newLayoutTransition(null)); - if (mEmbedded) { - mZenButtonsContainer.setBackground(null); - } else { - mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary); - } - mZenButtons.getChildAt(3).setVisibility(mEmbedded ? GONE : VISIBLE); - mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE); - updateWidgets(); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -179,37 +151,10 @@ public class ZenModePanel extends LinearLayout { Global.ZEN_MODE_ALARMS); mZenButtons.addButton(R.string.interruption_level_priority_twoline, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); - mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF); mZenButtons.setCallback(mZenButtonsCallback); - mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container); - mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null)); - - mZenSubhead = findViewById(R.id.zen_subhead); - mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider); - - mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed); - mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setExpanded(true); - } - }); - Interaction.register(mZenSubheadCollapsed, mInteractionCallback); - - mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded); - Interaction.register(mZenSubheadExpanded, mInteractionCallback); - - mMoreSettings = findViewById(R.id.zen_more_settings); - mMoreSettings.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - fireMoreSettings(); - } - }); - Interaction.register(mMoreSettings, mInteractionCallback); - mZenIntroduction = findViewById(R.id.zen_introduction); + mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message); mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm); mZenIntroductionConfirm.setOnClickListener(new OnClickListener() { @Override @@ -230,25 +175,25 @@ public class ZenModePanel extends LinearLayout { mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); - setLayoutTransition(newLayoutTransition(mTransitionHelper)); } private void confirmZenIntroduction() { - if (DEBUG) Log.d(TAG, "confirmZenIntroduction"); - Prefs.putBoolean(mContext, Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, true); + final String prefKey = prefKeyForConfirmation(getSelectedZen(Global.ZEN_MODE_OFF)); + if (prefKey == null) return; + if (DEBUG) Log.d(TAG, "confirmZenIntroduction " + prefKey); + Prefs.putBoolean(mContext, prefKey, true); mHandler.sendEmptyMessage(H.UPDATE_WIDGETS); } - private LayoutTransition newLayoutTransition(TransitionListener listener) { - final LayoutTransition transition = new LayoutTransition(); - transition.disableTransitionType(LayoutTransition.DISAPPEARING); - transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); - transition.disableTransitionType(LayoutTransition.APPEARING); - transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, mInterpolator); - if (listener != null) { - transition.addTransitionListener(listener); + private static String prefKeyForConfirmation(int zen) { + switch (zen) { + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: + return Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION; + case Global.ZEN_MODE_NO_INTERRUPTIONS: + return Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION; + default: + return null; } - return transition; } @Override @@ -260,7 +205,6 @@ public class ZenModePanel extends LinearLayout { mSessionZen = mAttachedZen; mTransitionHelper.clear(); setSessionExitCondition(copy(mExitCondition)); - refreshExitConditionText(); updateWidgets(); setRequestingConditions(!mHidden); } @@ -274,9 +218,6 @@ public class ZenModePanel extends LinearLayout { mAttachedZen = -1; mSessionZen = -1; setSessionExitCondition(null); - if (!mEmbedded) { - setExpanded(false); - } setRequestingConditions(false); mTransitionHelper.clear(); } @@ -359,7 +300,6 @@ public class ZenModePanel extends LinearLayout { for (int i = 0; i < mMaxConditions; i++) { mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false)); } - refreshExitConditionText(); mSessionZen = getSelectedZen(-1); handleUpdateManualRule(mController.getManualRule()); if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition); @@ -375,7 +315,6 @@ public class ZenModePanel extends LinearLayout { if (Objects.equals(mExitCondition, exitCondition)) return; mExitCondition = exitCondition; if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition)); - refreshExitConditionText(); updateWidgets(); } @@ -395,10 +334,6 @@ public class ZenModePanel extends LinearLayout { return condition == null ? null : condition.copy(); } - private void refreshExitConditionText() { - mExitConditionText = getExitConditionText(mContext, mExitCondition); - } - public static String getExitConditionText(Context context, Condition exitCondition) { if (exitCondition == null) { return foreverSummary(context); @@ -430,7 +365,7 @@ public class ZenModePanel extends LinearLayout { private void handleUpdateZen(int zen) { if (mSessionZen != -1 && mSessionZen != zen) { - setExpanded(mEmbedded && isShown() || !mEmbedded && zen != Global.ZEN_MODE_OFF); + setExpanded(isShown()); mSessionZen = zen; } mZenButtons.setSelectedValue(zen); @@ -480,30 +415,18 @@ public class ZenModePanel extends LinearLayout { return; } final int zen = getSelectedZen(Global.ZEN_MODE_OFF); - final boolean zenOff = zen == Global.ZEN_MODE_OFF; final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS; - final boolean expanded = !mHidden && mExpanded; - final boolean conditions = mEmbedded || !zenOff && expanded; - final boolean introduction = conditions && zenImportant && !mPrefs.mConfirmedIntroduction; + final boolean introduction = (zenImportant && !mPrefs.mConfirmedPriorityIntroduction + || zenNone && !mPrefs.mConfirmedSilenceIntroduction); mZenButtons.setVisibility(mHidden ? GONE : VISIBLE); - mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE); - mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE); - mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE); - mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE); - mZenConditions.setVisibility(conditions ? VISIBLE : GONE); - - if (zenNone) { - mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning); - mZenSubheadCollapsed.setText(mExitConditionText); - } else if (zenImportant) { - mZenSubheadExpanded.setText(R.string.zen_important_interruptions); - mZenSubheadCollapsed.setText(mExitConditionText); - } - mZenSubheadExpanded.setTextColor(zenNone && mPrefs.isNoneDangerous() - ? mSubheadWarningColor : mSubheadColor); mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE); + if (introduction) { + mZenIntroductionMessage.setText(zenImportant ? R.string.zen_priority_introduction + : R.string.zen_silence_introduction); + mZenIntroductionCustomize.setVisibility(zenImportant ? VISIBLE : GONE); + } } private static Condition parseExistingTimeCondition(Context context, Condition condition) { @@ -761,13 +684,13 @@ public class ZenModePanel extends LinearLayout { String modeText; switch(zen) { case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: - modeText = mContext.getString(R.string.zen_important_interruptions); + modeText = mContext.getString(R.string.interruption_level_priority); break; case Global.ZEN_MODE_NO_INTERRUPTIONS: - modeText = mContext.getString(R.string.zen_no_interruptions); + modeText = mContext.getString(R.string.interruption_level_none); break; case Global.ZEN_MODE_ALARMS: - modeText = mContext.getString(R.string.zen_alarms); + modeText = mContext.getString(R.string.interruption_level_alarms); break; default: return; @@ -837,12 +760,6 @@ public class ZenModePanel extends LinearLayout { setSessionExitCondition(copy(condition)); } - private void fireMoreSettings() { - if (mCallback != null) { - mCallback.onMoreSettings(); - } - } - private void fireInteraction() { if (mCallback != null) { mCallback.onInteraction(); @@ -887,7 +804,6 @@ public class ZenModePanel extends LinearLayout { } public interface Callback { - void onMoreSettings(); void onPrioritySettings(); void onInteraction(); void onExpanded(boolean expanded); @@ -907,7 +823,8 @@ public class ZenModePanel extends LinearLayout { private int mMinuteIndex; private int mNoneSelected; - private boolean mConfirmedIntroduction; + private boolean mConfirmedPriorityIntroduction; + private boolean mConfirmedSilenceIntroduction; private ZenPrefs() { mNoneDangerousThreshold = mContext.getResources() @@ -915,11 +832,8 @@ public class ZenModePanel extends LinearLayout { Prefs.registerListener(mContext, this); updateMinuteIndex(); updateNoneSelected(); - updateConfirmedIntroduction(); - } - - public boolean isNoneDangerous() { - return mNoneSelected < mNoneDangerousThreshold; + updateConfirmedPriorityIntroduction(); + updateConfirmedSilenceIntroduction(); } public void trackNoneSelected() { @@ -945,7 +859,8 @@ public class ZenModePanel extends LinearLayout { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { updateMinuteIndex(); updateNoneSelected(); - updateConfirmedIntroduction(); + updateConfirmedPriorityIntroduction(); + updateConfirmedSilenceIntroduction(); } private void updateMinuteIndex() { @@ -968,12 +883,22 @@ public class ZenModePanel extends LinearLayout { return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE); } - private void updateConfirmedIntroduction() { + private void updateConfirmedPriorityIntroduction() { final boolean confirmed = Prefs.getBoolean(mContext, Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, false); - if (confirmed == mConfirmedIntroduction) return; - mConfirmedIntroduction = confirmed; - if (DEBUG) Log.d(mTag, "Confirmed introduction: " + mConfirmedIntroduction); + if (confirmed == mConfirmedPriorityIntroduction) return; + mConfirmedPriorityIntroduction = confirmed; + if (DEBUG) Log.d(mTag, "Confirmed priority introduction: " + + mConfirmedPriorityIntroduction); + } + + private void updateConfirmedSilenceIntroduction() { + final boolean confirmed = Prefs.getBoolean(mContext, + Prefs.Key.DND_CONFIRMED_SILENCE_INTRODUCTION, false); + if (confirmed == mConfirmedSilenceIntroduction) return; + mConfirmedSilenceIntroduction = confirmed; + if (DEBUG) Log.d(mTag, "Confirmed silence introduction: " + + mConfirmedSilenceIntroduction); } } @@ -981,12 +906,16 @@ public class ZenModePanel extends LinearLayout { @Override public void onSelected(final Object value) { if (value != null && mZenButtons.isShown() && isAttachedToWindow()) { - if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value); + final int zen = (Integer) value; + if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + zen); final Uri realConditionId = getRealConditionId(mSessionExitCondition); AsyncTask.execute(new Runnable() { @Override public void run() { - mController.setZen((Integer) value, realConditionId, TAG + ".selectZen"); + mController.setZen(zen, realConditionId, TAG + ".selectZen"); + if (zen != Global.ZEN_MODE_OFF) { + Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, zen); + } } }); } |