summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/systemui/EventLogConstants.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java (renamed from packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java)34
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTile.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java181
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java284
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java212
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java190
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java222
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SecureCameraLaunchManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java256
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/HeadsUpAppearInterpolator.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java451
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java380
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/Util.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java260
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java179
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java191
83 files changed, 2981 insertions, 1304 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
index c8af2d4..43a1be1 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
@@ -34,4 +34,10 @@ public class EventLogConstants {
public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6;
/** The user tapped a notification, needs to tap again to launch. */
public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7;
+ /** The user swiped down to open quick settings, from keyguard. */
+ public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8;
+ /** The user swiped down to open quick settings, from shade. */
+ public static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9;
+ /** The user tapped on the status bar to open quick settings, from shade. */
+ public static final int SYSUI_TAP_TO_OPEN_QS = 10;
}
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/assist/AssistGestureManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 36be355..08659e9 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -33,11 +33,11 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
/**
- * Class to manage everything around the assist gesture.
+ * Class to manage everything related to assist in SystemUI.
*/
-public class AssistGestureManager {
+public class AssistManager {
- private static final String TAG = "AssistGestureManager";
+ private static final String TAG = "AssistManager";
private static final String ASSIST_ICON_METADATA_NAME =
"com.android.systemui.action_assist_icon";
@@ -77,7 +77,7 @@ public class AssistGestureManager {
}
};
- public AssistGestureManager(PhoneStatusBar bar, Context context) {
+ public AssistManager(PhoneStatusBar bar, Context context) {
mContext = context;
mBar = bar;
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -194,16 +194,35 @@ public class AssistGestureManager {
}
}
+ public void launchVoiceAssistFromKeyguard() {
+ try {
+ mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e);
+ }
+ }
+
private boolean getVoiceInteractorSupportsAssistGesture() {
try {
- return mVoiceInteractionManagerService.activeServiceSupportsAssistGesture();
+ return mVoiceInteractionManagerService != null
+ && mVoiceInteractionManagerService.activeServiceSupportsAssist();
} catch (RemoteException e) {
Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e);
return false;
}
}
- private ComponentName getVoiceInteractorComponentName() {
+ public boolean canVoiceAssistBeLaunchedFromKeyguard() {
+ try {
+ return mVoiceInteractionManagerService != null
+ && mVoiceInteractionManagerService.activeServiceSupportsLaunchFromKeyguard();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to call activeServiceSupportsLaunchFromKeyguard", e);
+ return false;
+ }
+ }
+
+ public ComponentName getVoiceInteractorComponentName() {
try {
return mVoiceInteractionManagerService.getActiveServiceComponentName();
} catch (RemoteException e) {
@@ -214,7 +233,8 @@ public class AssistGestureManager {
private boolean isVoiceSessionRunning() {
try {
- return mVoiceInteractionManagerService.isSessionRunning();
+ return mVoiceInteractionManagerService != null
+ && mVoiceInteractionManagerService.isSessionRunning();
} catch (RemoteException e) {
Log.w(TAG, "Failed to call isSessionRunning", e);
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 7b555fc..74962ec 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());
@@ -1330,7 +1335,7 @@ public class KeyguardViewMediator extends SystemUI {
// Don't actually hide the Keyguard at the moment, wait for window
// manager until it tells us it's safe to do so with
// startKeyguardExitAnimation.
- mWM.keyguardGoingAway(
+ ActivityManagerNative.getDefault().keyguardGoingAway(
mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock(),
mStatusBarKeyguardViewManager.isGoingToNotificationShade());
} catch (RemoteException e) {
@@ -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/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index d8e3984..f59e864 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -110,21 +110,15 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
}
private void handleRefreshState() {
- if (mSecurityController.hasDeviceOwner()) {
+ boolean hasDeviceOwner = mSecurityController.hasDeviceOwner();
+ boolean hasVpn = mSecurityController.isVpnEnabled();
+
+ mIsVisible = (hasVpn || hasDeviceOwner);
+ mIsIconVisible = hasVpn;
+ if (hasDeviceOwner) {
mFooterTextId = R.string.device_owned_footer;
- mIsVisible = true;
- mIsIconVisible = false;
- } else if (mSecurityController.hasProfileOwner()) {
- mFooterTextId = R.string.profile_owned_footer;
- mIsVisible = true;
- mIsIconVisible = false;
- } else if (mSecurityController.isVpnEnabled()) {
- mFooterTextId = R.string.vpn_footer;
- mIsVisible = true;
- mIsIconVisible = true;
} else {
- mIsVisible = false;
- mIsIconVisible = false;
+ mFooterTextId = R.string.vpn_footer;
}
mMainHandler.post(mUpdateDisplayState);
}
@@ -162,37 +156,17 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
private String getMessage(boolean hasDeviceOwner, boolean hasProfile, boolean hasVpn) {
if (hasDeviceOwner) {
- if (hasProfile) {
- if (hasVpn) {
- return mContext.getString(
- R.string.monitoring_description_vpn_device_and_profile_owned,
- mSecurityController.getDeviceOwnerName(),
- mSecurityController.getProfileOwnerName());
- } else {
- return mContext.getString(
- R.string.monitoring_description_device_and_profile_owned,
- mSecurityController.getDeviceOwnerName(),
- mSecurityController.getProfileOwnerName());
- }
- } else {
- if (hasVpn) {
- return mContext.getString(R.string.monitoring_description_vpn_device_owned,
- mSecurityController.getDeviceOwnerName());
- } else {
- return mContext.getString(R.string.monitoring_description_device_owned,
- mSecurityController.getDeviceOwnerName());
- }
- }
- } else if (hasProfile) {
if (hasVpn) {
- return mContext.getString(
- R.string.monitoring_description_vpn_profile_owned,
- mSecurityController.getProfileOwnerName());
+ return mContext.getString(R.string.monitoring_description_vpn_device_owned,
+ mSecurityController.getDeviceOwnerName());
} else {
- return mContext.getString(
- R.string.monitoring_description_profile_owned,
- mSecurityController.getProfileOwnerName());
+ return mContext.getString(R.string.monitoring_description_device_owned,
+ mSecurityController.getDeviceOwnerName());
}
+ } else if (hasProfile) {
+ return mContext.getString(
+ R.string.monitoring_description_vpn_profile_owned,
+ mSecurityController.getProfileOwnerName());
} else {
return mContext.getString(R.string.monitoring_description_vpn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index b5c1ca8..b4ae20d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -33,6 +33,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.DetailAdapter;
@@ -49,12 +50,12 @@ public class QSPanel extends ViewGroup {
private static final float TILE_ASPECT = 1.2f;
private final Context mContext;
- private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
+ protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
private final View mDetail;
private final ViewGroup mDetailContent;
private final TextView mDetailSettingsButton;
private final TextView mDetailDoneButton;
- private final View mBrightnessView;
+ protected final View mBrightnessView;
private final QSDetailClipper mClipper;
private final H mHandler = new H();
@@ -182,8 +183,11 @@ public class QSPanel extends ViewGroup {
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
+ MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, mExpanded);
if (!mExpanded) {
closeDetail();
+ } else {
+ logTiles();
}
}
@@ -243,6 +247,12 @@ public class QSPanel extends ViewGroup {
}
}
+ private void drawTile(TileRecord r, QSTile.State state) {
+ final int visibility = state.visible ? VISIBLE : GONE;
+ setTileVisibility(r.tileView, visibility);
+ r.tileView.onStateChanged(state);
+ }
+
private void addTile(final QSTile<?> tile) {
final TileRecord r = new TileRecord();
r.tile = tile;
@@ -251,9 +261,9 @@ public class QSPanel extends ViewGroup {
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
- int visibility = state.visible ? VISIBLE : GONE;
- setTileVisibility(r.tileView, visibility);
- r.tileView.onStateChanged(state);
+ if (!r.openingDetail) {
+ drawTile(r, state);
+ }
}
@Override
public void onShowDetail(boolean show) {
@@ -365,9 +375,14 @@ public class QSPanel extends ViewGroup {
mDetailContent.removeAllViews();
mDetail.bringToFront();
mDetailContent.addView(r.detailView);
+ MetricsLogger.visible(mContext, detailAdapter.getMetricsCategory());
setDetailRecord(r);
listener = mHideGridContentWhenDone;
+ if (r instanceof TileRecord) {
+ ((TileRecord) r).openingDetail = true;
+ }
} else {
+ MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
mClosingDetail = true;
setGridContentVisibility(true);
listener = mTeardownDetailWhenDone;
@@ -387,9 +402,21 @@ public class QSPanel extends ViewGroup {
}
}
mBrightnessView.setVisibility(newVis);
+ if (mGridContentVisible != visible) {
+ MetricsLogger.visibility(mContext, MetricsLogger.QS_PANEL, newVis);
+ }
mGridContentVisible = visible;
}
+ private void logTiles() {
+ for (int i = 0; i < mRecords.size(); i++) {
+ TileRecord tileRecord = mRecords.get(i);
+ if (tileRecord.tile.getState().visible) {
+ MetricsLogger.visible(mContext, tileRecord.tile.getMetricsCategory());
+ }
+ }
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -533,12 +560,13 @@ public class QSPanel extends ViewGroup {
DetailAdapter detailAdapter;
}
- private static final class TileRecord extends Record {
- QSTile<?> tile;
- QSTileView tileView;
- int row;
- int col;
- boolean scanState;
+ protected static final class TileRecord extends Record {
+ public QSTile<?> tile;
+ public QSTileView tileView;
+ public int row;
+ public int col;
+ public boolean scanState;
+ public boolean openingDetail;
}
private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
@@ -554,6 +582,7 @@ public class QSPanel extends ViewGroup {
// If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
// called, this will avoid accidentally turning off the grid when we don't want to.
animation.removeListener(this);
+ redrawTile();
};
@Override
@@ -561,6 +590,15 @@ public class QSPanel extends ViewGroup {
// Only hide content if still in detail state.
if (mDetailRecord != null) {
setGridContentVisibility(false);
+ redrawTile();
+ }
+ }
+
+ private void redrawTile() {
+ if (mDetailRecord instanceof TileRecord) {
+ final TileRecord tileRecord = (TileRecord) mDetailRecord;
+ tileRecord.openingDetail = false;
+ drawTile(tileRecord, tileRecord.tile.getState());
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index b9574dc..3b217df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -24,11 +24,13 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.qs.QSTile.State;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
@@ -69,6 +71,15 @@ public abstract class QSTile<TState extends State> implements Listenable {
abstract protected void handleClick();
abstract protected void handleUpdateState(TState state, Object arg);
+ /**
+ * Declare the category of this tile.
+ *
+ * Categories are defined in {@link com.android.internal.logging.MetricsLogger}
+ * or if there is no relevant existing category you may define one in
+ * {@link com.android.systemui.qs.QSTile}.
+ */
+ abstract public int getMetricsCategory();
+
protected QSTile(Host host) {
mHost = host;
mContext = host.getContext();
@@ -97,6 +108,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
View createDetailView(Context context, View convertView, ViewGroup parent);
Intent getSettingsIntent();
void setToggleState(boolean state);
+ int getMetricsCategory();
}
// safe to call from any thread
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 2bc31fc..49f8d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -23,6 +23,7 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.provider.Settings.Global;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.qs.QSTile;
@@ -55,6 +56,7 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
@Override
public void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
setEnabled(!mState.value);
mEnable.setAllowAnimation(true);
mDisable.setAllowAnimation(true);
@@ -85,6 +87,11 @@ public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_AIRPLANEMODE;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_airplane_changed_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index b42b5f6..ed954bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -25,6 +25,7 @@ import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
@@ -75,6 +76,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
final boolean isEnabled = (Boolean)mState.value;
+ MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setBluetoothEnabled(!isEnabled);
}
@@ -132,6 +134,11 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_BLUETOOTH;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
@@ -177,11 +184,17 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
@Override
public void setToggleState(boolean state) {
+ MetricsLogger.action(mContext, MetricsLogger.QS_BLUETOOTH_TOGGLE, state);
mController.setBluetoothEnabled(state);
showDetail(false);
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_BLUETOOTH_DETAILS;
+ }
+
+ @Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
mItems.setTagSuffix("Bluetooth");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 5bf6fb5..c06ea66 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -24,6 +24,7 @@ import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
@@ -85,6 +86,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory());
showDetail(true);
}
@@ -113,6 +115,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_CAST;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (!mState.value) {
// We only announce when it's turned off to avoid vocal overflow.
@@ -164,6 +171,11 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_CAST_DETAILS;
+ }
+
+ @Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
mItems.setTagSuffix("Cast");
@@ -234,6 +246,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
@Override
public void onDetailItemClick(Item item) {
if (item == null || item.tag == null) return;
+ MetricsLogger.action(mContext, MetricsLogger.QS_CAST_SELECT);
final CastDevice device = (CastDevice) item.tag;
mController.startCasting(device);
}
@@ -241,6 +254,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> {
@Override
public void onDetailItemDisconnect(Item item) {
if (item == null || item.tag == null) return;
+ MetricsLogger.action(mContext, MetricsLogger.QS_CAST_DISCONNECT);
final CastDevice device = (CastDevice) item.tag;
mController.stopCasting(device);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 30f92b9..1721335 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -24,6 +24,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTileView;
@@ -75,6 +76,7 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
@Override
protected void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory());
if (mDataController.isMobileDataSupported()) {
showDetail(true);
} else {
@@ -118,6 +120,11 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
state.label);
}
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_CELLULAR;
+ }
+
// Remove the period from the network name
public static String removeTrailingPeriod(String string) {
if (string == null) return null;
@@ -223,10 +230,16 @@ public class CellularTile extends QSTile<QSTile.SignalState> {
@Override
public void setToggleState(boolean state) {
+ MetricsLogger.action(mContext, MetricsLogger.QS_CELLULAR_TOGGLE, state);
mDataController.setMobileDataEnabled(state);
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_DATAUSAGEDETAIL;
+ }
+
+ @Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
final DataUsageDetailView v = (DataUsageDetailView) (convertView != null
? convertView
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 4a33f55..c6fc6ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import android.provider.Settings.Secure;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -86,6 +87,7 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
mEnable.setAllowAnimation(true);
mDisable.setAllowAnimation(true);
@@ -115,6 +117,11 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_COLORINVERSION;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(
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..f4d6f04 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,6 +29,7 @@ import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -37,7 +38,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";
@@ -84,10 +89,12 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
@Override
public void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
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);
showDetail(true);
}
}
@@ -95,7 +102,9 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
- state.value = zen != Global.ZEN_MODE_OFF;
+ final boolean newValue = zen != Global.ZEN_MODE_OFF;
+ final boolean valueChanged = state.value != newValue;
+ state.value = newValue;
state.visible = isVisible(mContext);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
@@ -105,7 +114,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
R.string.accessibility_quick_settings_dnd_priority_on);
break;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
- state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd_none_on);
@@ -126,6 +135,14 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
if (mShowingDetail && !state.value) {
showDetail(false);
}
+ if (valueChanged) {
+ fireToggleStateChanged(state.value);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_DND;
}
@Override
@@ -196,6 +213,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
@Override
public void setToggleState(boolean state) {
+ MetricsLogger.action(mContext, MetricsLogger.QS_DND_TOGGLE, state);
if (!state) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
showDetail(false);
@@ -203,14 +221,19 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_DND_DETAILS;
+ }
+
+ @Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
: (ZenModePanel) LayoutInflater.from(context).inflate(
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 +248,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/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index cb78deb..0369ab5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import android.app.ActivityManager;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.FlashlightController;
@@ -62,6 +63,7 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
if (ActivityManager.isUserAMonkey()) {
return;
}
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
boolean newState = !mState.value;
refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
mFlashlightController.setFlashlight(newState);
@@ -84,6 +86,11 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_FLASHLIGHT;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_flashlight_changed_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 6063f80..f28a24b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -20,6 +20,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.qs.UsageTracker;
@@ -69,6 +70,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
final boolean isEnabled = (Boolean) mState.value;
+ MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setHotspotEnabled(!isEnabled);
mEnable.setAllowAnimation(true);
mDisable.setAllowAnimation(true);
@@ -97,6 +99,11 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_HOTSPOT;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_hotspot_changed_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 2736530..19f4df6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -29,6 +29,7 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.qs.QSTile;
import java.util.Arrays;
@@ -42,6 +43,7 @@ public class IntentTile extends QSTile<QSTile.State> {
private PendingIntent mOnLongClick;
private String mOnLongClickUri;
private int mCurrentUserId;
+ private String mIntentPackage;
private IntentTile(Host host, String action) {
super(host);
@@ -82,6 +84,7 @@ public class IntentTile extends QSTile<QSTile.State> {
@Override
protected void handleClick() {
+ MetricsLogger.action(mContext, getMetricsCategory(), mIntentPackage);
sendIntent("click", mOnClick, mOnClickUri);
}
@@ -133,6 +136,13 @@ public class IntentTile extends QSTile<QSTile.State> {
mOnClickUri = intent.getStringExtra("onClickUri");
mOnLongClick = intent.getParcelableExtra("onLongClick");
mOnLongClickUri = intent.getStringExtra("onLongClickUri");
+ mIntentPackage = intent.getStringExtra("package");
+ mIntentPackage = mIntentPackage == null ? "" : mIntentPackage;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_INTENT;
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 11ec722..e6fade4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -59,6 +60,7 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
final boolean wasEnabled = (Boolean) mState.value;
+ MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
mEnable.setAllowAnimation(true);
mDisable.setAllowAnimation(true);
@@ -87,6 +89,11 @@ public class LocationTile extends QSTile<QSTile.BooleanState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_LOCATION;
+ }
+
+ @Override
protected String composeChangeAnnouncement() {
if (mState.value) {
return mContext.getString(R.string.accessibility_quick_settings_location_changed_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index f46b9a6..7c378f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import android.content.res.Configuration;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.RotationLockController;
@@ -59,6 +60,7 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
@Override
protected void handleClick() {
if (mController == null) return;
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
final boolean newState = !mState.value;
mController.setRotationLocked(newState);
refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
@@ -92,6 +94,11 @@ public class RotationLockTile extends QSTile<QSTile.BooleanState> {
R.string.accessibility_rotation_lock_off);
}
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_ROTATIONLOCK;
+ }
+
/**
* Get the correct accessibility string based on the state
*
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 6bad652..d4f54b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -84,6 +85,7 @@ public class UserDetailView extends PseudoGridView {
public void onClick(View view) {
UserSwitcherController.UserRecord tag =
(UserSwitcherController.UserRecord) view.getTag();
+ MetricsLogger.action(mContext, MetricsLogger.QS_SWITCH_USER);
switchTo(tag);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index d589366..c3f9e33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -26,6 +26,7 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.logging.MetricsLogger;
import com.android.settingslib.wifi.AccessPoint;
import com.android.systemui.R;
import com.android.systemui.qs.QSDetailItems;
@@ -94,6 +95,7 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
@Override
protected void handleClick() {
mState.copyTo(mStateBeforeClick);
+ MetricsLogger.action(mContext, getMetricsCategory(), !mState.enabled);
mController.setWifiEnabled(!mState.enabled);
}
@@ -159,6 +161,11 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_WIFI;
+ }
+
+ @Override
protected boolean shouldAnnouncementBeDelayed() {
return mStateBeforeClick.enabled == mState.enabled;
}
@@ -269,11 +276,17 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
@Override
public void setToggleState(boolean state) {
if (DEBUG) Log.d(TAG, "setToggleState " + state);
+ MetricsLogger.action(mContext, MetricsLogger.QS_WIFI_TOGGLE, state);
mController.setWifiEnabled(state);
showDetail(false);
}
@Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_WIFI_DETAILS;
+ }
+
+ @Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
if (DEBUG) Log.d(TAG, "createDetailView convertView=" + (convertView != null));
mAccessPoints = null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 1001feb..ad97f91 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -39,7 +39,6 @@ import com.android.systemui.R;
import com.android.systemui.recents.misc.DebugTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -392,15 +391,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
registerReceiver(mSystemBroadcastReceiver, filter);
-
- // Private API calls to make the shadows look better
- try {
- Utilities.setShadowProperty("ambientRatio", String.valueOf(1.5f));
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
}
/** Inflates the debug overlay if debug mode is enabled. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index d60df9c..e3fb16a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -438,6 +438,33 @@ public class SystemServicesProxy {
return info.loadLabel(mPm).toString();
}
+ /** Returns the application label */
+ public String getApplicationLabel(Intent baseIntent, int userId) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return "Recent Task";
+ }
+
+ ResolveInfo ri = mPm.resolveActivityAsUser(baseIntent, 0, userId);
+ CharSequence label = (ri != null) ? ri.loadLabel(mPm) : null;
+ return (label != null) ? label.toString() : null;
+ }
+
+ /** Returns the content description for a given task */
+ public String getContentDescription(Intent baseIntent, int userId, String activityLabel,
+ Resources res) {
+ String applicationLabel = getApplicationLabel(baseIntent, userId);
+ if (applicationLabel == null) {
+ return getBadgedLabel(activityLabel, userId);
+ }
+ String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
+ return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
+ : res.getString(R.string.accessibility_recents_task_header,
+ badgedApplicationLabel, activityLabel);
+ }
+
/**
* Returns the activity icon for the ActivityInfo for a user, badging if
* necessary.
@@ -464,6 +491,16 @@ public class SystemServicesProxy {
return icon;
}
+ /**
+ * Returns the given label for a user, badging if necessary.
+ */
+ public String getBadgedLabel(String label, int userId) {
+ if (userId != UserHandle.myUserId()) {
+ label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
+ }
+ return label;
+ }
+
/** Returns the package name of the home activity. */
public String getHomeActivityPackageName() {
if (mPm == null) return null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 84544ff..e810410 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -22,27 +22,11 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.View;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
/* Common code */
public class Utilities {
- // Reflection methods for altering shadows
- private static Method sPropertyMethod;
- static {
- try {
- Class<?> c = Class.forName("android.view.DisplayListCanvas");
- sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
- if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- }
-
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(Rect r, float scale) {
if (scale != 1.0f) {
@@ -163,12 +147,6 @@ public class Utilities {
(1f - overlayAlpha) * Color.blue(overlayColor)));
}
- /** Sets some private shadow properties. */
- public static void setShadowProperty(String property, String value)
- throws IllegalAccessException, InvocationTargetException {
- sPropertyMethod.invoke(null, property, value);
- }
-
/**
* Cancels an animation ensuring that if it has listeners, onCancel and onEnd
* are not called.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 5d98dda..40cd211 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -130,6 +130,8 @@ public class RecentsTaskLoadPlan {
// Load the label, icon, and color
String activityLabel = loader.getAndUpdateActivityLabel(taskKey, t.taskDescription,
mSystemServicesProxy, infoHandle);
+ String contentDescription = loader.getAndUpdateContentDescription(taskKey,
+ activityLabel, mSystemServicesProxy, res);
Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
mSystemServicesProxy, res, infoHandle, false);
int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig);
@@ -148,9 +150,9 @@ public class RecentsTaskLoadPlan {
// Add the task to the stack
Task task = new Task(taskKey, (t.id != RecentsTaskLoader.INVALID_TASK_ID),
- t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel, activityIcon,
- activityColor, (i == (taskCount - 1)), mConfig.lockToAppEnabled, icon,
- iconFilename);
+ t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel, contentDescription,
+ activityIcon, activityColor, (i == (taskCount - 1)), mConfig.lockToAppEnabled,
+ icon, iconFilename);
task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 3192fe6..b2aa2b6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -259,6 +259,7 @@ public class RecentsTaskLoader {
DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
StringLruCache mActivityLabelCache;
+ StringLruCache mContentDescriptionCache;
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
@@ -298,6 +299,7 @@ public class RecentsTaskLoader {
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
mActivityLabelCache = new StringLruCache(100);
+ mContentDescriptionCache = new StringLruCache(100);
mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
mDefaultThumbnail, mDefaultApplicationIcon);
}
@@ -348,6 +350,24 @@ public class RecentsTaskLoader {
return label;
}
+ /** Returns the content description using as many cached values as we can. */
+ public String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
+ SystemServicesProxy ssp, Resources res) {
+ // Return the cached content description if it exists
+ String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
+ if (label != null) {
+ return label;
+ }
+ label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
+ if (label != null) {
+ mContentDescriptionCache.put(taskKey, label);
+ } else {
+ Log.w(TAG, "Missing content description for " + taskKey.baseIntent.getComponent()
+ + " u=" + taskKey.userId);
+ }
+ return label;
+ }
+
/** Returns the activity icon using as many cached values as we can. */
public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
ActivityManager.TaskDescription td, SystemServicesProxy ssp,
@@ -541,6 +561,7 @@ public class RecentsTaskLoader {
mApplicationIconCache.evictAll();
// The cache is small, only clear the label cache when we are critical
mActivityLabelCache.evictAll();
+ mContentDescriptionCache.evictAll();
break;
default:
break;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 0cd55d7..c14adf4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -124,6 +124,7 @@ public class Task {
public boolean isLaunchTarget;
public Drawable applicationIcon;
public Drawable activityIcon;
+ public String contentDescription;
public String activityLabel;
public int colorPrimary;
public boolean useLightOnPrimaryColor;
@@ -140,8 +141,8 @@ public class Task {
}
public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
- String activityTitle, Drawable activityIcon, int colorPrimary,
- boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
+ String activityTitle, String contentDescription, Drawable activityIcon,
+ int colorPrimary, boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
String iconFilename) {
boolean isInAffiliationGroup = (taskAffiliation != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
@@ -149,6 +150,7 @@ public class Task {
this.taskAffiliation = taskAffiliation;
this.taskAffiliationColor = taskAffiliationColor;
this.activityLabel = activityTitle;
+ this.contentDescription = contentDescription;
this.activityIcon = activityIcon;
this.colorPrimary = hasAffiliationGroupColor ? taskAffiliationColor : colorPrimary;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -166,6 +168,7 @@ public class Task {
this.taskAffiliation = o.taskAffiliation;
this.taskAffiliationColor = o.taskAffiliationColor;
this.activityLabel = o.activityLabel;
+ this.contentDescription = o.contentDescription;
this.activityIcon = o.activityIcon;
this.colorPrimary = o.colorPrimary;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 60a91bf..f397bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -190,10 +190,12 @@ public class TaskViewHeader extends FrameLayout {
} else if (t.applicationIcon != null) {
mApplicationIcon.setImageDrawable(t.applicationIcon);
}
- mApplicationIcon.setContentDescription(t.activityLabel);
+ mApplicationIcon.setContentDescription(t.contentDescription);
if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
mActivityDescription.setText(t.activityLabel);
}
+ mActivityDescription.setContentDescription(t.contentDescription);
+
// Try and apply the system ui tint
int existingBgColor = getBackgroundColor();
if (existingBgColor != t.colorPrimary) {
@@ -207,7 +209,7 @@ public class TaskViewHeader extends FrameLayout {
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
- t.activityLabel));
+ t.contentDescription));
mMoveTaskButton.setVisibility((mConfig.multiStackEnabled) ? View.VISIBLE : View.INVISIBLE);
if (mConfig.multiStackEnabled) {
updateResizeTaskBarIcon(t);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7271469..2913c7d 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;
@@ -237,6 +238,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
+ private NotificationClicker mNotificationClicker = new NotificationClicker();
+
@Override // NotificationData.Environment
public boolean isDeviceProvisioned() {
return mDeviceProvisioned;
@@ -392,11 +395,6 @@ public abstract class BaseStatusBar extends SystemUI implements
Toast.LENGTH_SHORT).show();
}
}
- } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
- action)) {
- mUsersAllowingPrivateNotifications.clear();
- updateLockscreenNotificationSetting();
- updateNotifications();
} else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
NotificationManager noMan = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -416,6 +414,19 @@ public abstract class BaseStatusBar extends SystemUI implements
}
};
+ private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
+ isCurrentProfile(getSendingUserId())) {
+ mUsersAllowingPrivateNotifications.clear();
+ updateLockscreenNotificationSetting();
+ updateNotifications();
+ }
+ }
+ };
+
private final NotificationListenerService mNotificationListener =
new NotificationListenerService() {
@Override
@@ -628,9 +639,13 @@ public abstract class BaseStatusBar extends SystemUI implements
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(BANNER_ACTION_CANCEL);
filter.addAction(BANNER_ACTION_SETUP);
- filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
+ IntentFilter allUsersFilter = new IntentFilter();
+ allUsersFilter.addAction(
+ DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
+ null, null);
updateCurrentProfilesCache();
}
@@ -639,7 +654,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 +723,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 +798,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 +824,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 +1150,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.
@@ -1301,13 +1306,7 @@ public abstract class BaseStatusBar extends SystemUI implements
row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
- PendingIntent contentIntent = sbn.getNotification().contentIntent;
- if (contentIntent != null) {
- final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey());
- row.setOnClickListener(listener);
- } else {
- row.setOnClickListener(null);
- }
+ mNotificationClicker.register(row, sbn);
// set up the adaptive layout
View contentViewLocal = null;
@@ -1348,8 +1347,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 +1455,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 +1544,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);
}
}
@@ -1569,35 +1567,38 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- public NotificationClicker makeClicker(PendingIntent intent, String notificationKey) {
- return new NotificationClicker(intent, notificationKey);
- }
+ private final class NotificationClicker implements View.OnClickListener {
+ public void onClick(final View v) {
+ if (!(v instanceof ExpandableNotificationRow)) {
+ Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
+ return;
+ }
- protected class NotificationClicker implements View.OnClickListener {
- private PendingIntent mIntent;
- private final String mNotificationKey;
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ final StatusBarNotification sbn = row.getStatusBarNotification();
+ if (sbn == null) {
+ Log.e(TAG, "NotificationClicker called on an unclickable notification,");
+ return;
+ }
- public NotificationClicker(PendingIntent intent, String notificationKey) {
- mIntent = intent;
- mNotificationKey = notificationKey;
- }
+ final PendingIntent intent = sbn.getNotification().contentIntent;
+ final String notificationKey = sbn.getKey();
- public void onClick(final View v) {
if (NOTIFICATION_CLICK_DEBUG) {
- Log.d(TAG, "Clicked on content of " + mNotificationKey);
+ Log.d(TAG, "Clicked on content of " + notificationKey);
}
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
- final boolean afterKeyguardGone = mIntent.isActivity()
- && PreviewInflater.wouldLaunchResolverActivity(mContext, mIntent.getIntent(),
+ final boolean afterKeyguardGone = intent.isActivity()
+ && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
dismissKeyguardThenExecute(new OnDismissAction() {
public boolean onDismiss() {
- if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(mNotificationKey)) {
+ if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
// Release the HUN notification to the shade.
//
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will
// become canceled shortly by NoMan, but we can't assume that.
- mHeadsUpManager.releaseImmediately(mNotificationKey);
+ mHeadsUpManager.releaseImmediately(notificationKey);
}
new Thread() {
@Override
@@ -1616,9 +1617,9 @@ public abstract class BaseStatusBar extends SystemUI implements
} catch (RemoteException e) {
}
- if (mIntent != null) {
+ if (intent != null) {
try {
- mIntent.send();
+ intent.send();
} catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here.
// Just log the exception message.
@@ -1626,14 +1627,14 @@ public abstract class BaseStatusBar extends SystemUI implements
// TODO: Dismiss Keyguard.
}
- if (mIntent.isActivity()) {
+ if (intent.isActivity()) {
overrideActivityPendingAppTransition(keyguardShowing
&& !afterKeyguardGone);
}
}
try {
- mBarService.onNotificationClick(mNotificationKey);
+ mBarService.onNotificationClick(notificationKey);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@@ -1645,10 +1646,19 @@ public abstract class BaseStatusBar extends SystemUI implements
true /* force */, true /* delayed */);
visibilityChanged(false);
- return mIntent != null && mIntent.isActivity();
+ return intent != null && intent.isActivity();
}
}, afterKeyguardGone);
}
+
+ public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
+ final PendingIntent contentIntent = sbn.getNotification().contentIntent;
+ if (contentIntent != null) {
+ row.setOnClickListener(this);
+ } else {
+ row.setOnClickListener(null);
+ }
+ }
}
public void animateCollapsePanels(int flags, boolean force) {
@@ -1701,7 +1711,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 +1904,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 +1932,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 +1956,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 +1972,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 +1985,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 +2004,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 +2044,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);
}
@@ -2047,13 +2057,8 @@ public abstract class BaseStatusBar extends SystemUI implements
publicContentView.reapply(mContext, entry.getPublicContentView(), mOnClickHandler);
}
// update the contentIntent
- final PendingIntent contentIntent = notification.getNotification().contentIntent;
- if (contentIntent != null) {
- final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey());
- entry.row.setOnClickListener(listener);
- } else {
- entry.row.setOnClickListener(null);
- }
+ mNotificationClicker.register(entry.row, notification);
+
entry.row.setStatusBarNotification(notification);
entry.row.notifyContentUpdated();
entry.row.resetHeight();
@@ -2062,7 +2067,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/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 4542054..80fdd28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -157,7 +157,8 @@ public class CommandQueue extends IStatusBar.Stub {
public void setSystemUiVisibility(int vis, int mask) {
synchronized (mList) {
- mHandler.removeMessages(MSG_SET_SYSTEMUI_VISIBILITY);
+ // Don't coalesce these, since it might have one time flags set such as
+ // STATUS_BAR_UNHIDE which might get lost.
mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget();
}
}
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/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index e632cc8..17e2cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -59,13 +59,6 @@ public abstract class ExpandableView extends FrameLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int ownMaxHeight = mMaxViewHeight;
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
- boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
- if (hasFixedHeight || isHeightLimited) {
- int size = MeasureSpec.getSize(heightMeasureSpec);
- ownMaxHeight = Math.min(ownMaxHeight, size);
- }
int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
int maxChildHeight = 0;
int childCount = getChildCount();
@@ -92,8 +85,7 @@ public abstract class ExpandableView extends FrameLayout {
mMatchParentViews.add(child);
}
}
- int ownHeight = hasFixedHeight ? ownMaxHeight :
- isHeightLimited ? Math.min(ownMaxHeight, maxChildHeight) : maxChildHeight;
+ int ownHeight = Math.min(ownMaxHeight, maxChildHeight);
newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
for (View child : mMatchParentViews) {
child.measure(getChildMeasureSpec(
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/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index b2bb021..f6629dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -53,18 +53,21 @@ public class SignalClusterView
private boolean mNoSimsVisible = false;
private boolean mVpnVisible = false;
+ private boolean mEthernetVisible = false;
+ private int mEthernetIconId = 0;
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mAirplaneContentDescription;
private String mWifiDescription;
+ private String mEthernetDescription;
private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
private int mIconTint = Color.WHITE;
private float mDarkIntensity;
- ViewGroup mWifiGroup;
- ImageView mVpn, mWifi, mAirplane, mNoSims, mWifiDark, mNoSimsDark;
+ ViewGroup mEthernetGroup, mWifiGroup;
+ ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
@@ -116,6 +119,9 @@ public class SignalClusterView
super.onAttachedToWindow();
mVpn = (ImageView) findViewById(R.id.vpn);
+ mEthernetGroup = (ViewGroup) findViewById(R.id.ethernet_combo);
+ mEthernet = (ImageView) findViewById(R.id.ethernet);
+ mEthernetDark = (ImageView) findViewById(R.id.ethernet_dark);
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark);
@@ -136,6 +142,8 @@ public class SignalClusterView
@Override
protected void onDetachedFromWindow() {
mVpn = null;
+ mEthernetGroup = null;
+ mEthernet = null;
mWifiGroup = null;
mWifi = null;
mAirplane = null;
@@ -183,6 +191,15 @@ public class SignalClusterView
}
@Override
+ public void setEthernetIndicators(boolean visible, int icon, String contentDescription) {
+ mEthernetVisible = visible;
+ mEthernetIconId = icon;
+ mEthernetDescription = contentDescription;
+
+ apply();
+ }
+
+ @Override
public void setNoSims(boolean show) {
mNoSimsVisible = show;
}
@@ -234,6 +251,9 @@ public class SignalClusterView
public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
// Standard group layout onPopulateAccessibilityEvent() implementations
// ignore content description, so populate manually
+ if (mEthernetVisible && mEthernetGroup != null &&
+ mEthernetGroup.getContentDescription() != null)
+ event.getText().add(mEthernetGroup.getContentDescription());
if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
event.getText().add(mWifiGroup.getContentDescription());
for (PhoneState state : mPhoneStates) {
@@ -246,6 +266,10 @@ public class SignalClusterView
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
+ if (mEthernet != null) {
+ mEthernet.setImageDrawable(null);
+ }
+
if (mWifi != null) {
mWifi.setImageDrawable(null);
}
@@ -277,6 +301,21 @@ public class SignalClusterView
mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE);
if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
+
+ if (mEthernetVisible) {
+ mEthernet.setImageResource(mEthernetIconId);
+ mEthernetDark.setImageResource(mEthernetIconId);
+ mEthernetGroup.setContentDescription(mEthernetDescription);
+ mEthernetGroup.setVisibility(View.VISIBLE);
+ } else {
+ mEthernetGroup.setVisibility(View.GONE);
+ }
+
+ if (DEBUG) Log.d(TAG,
+ String.format("ethernet: %s",
+ (mEthernetVisible ? "VISIBLE" : "GONE")));
+
+
if (mWifiVisible) {
mWifi.setImageResource(mWifiStrengthId);
mWifiDark.setImageResource(mWifiStrengthId);
@@ -327,7 +366,7 @@ public class SignalClusterView
mNoSimsDark.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
- || anyMobileVisible || mVpnVisible;
+ || anyMobileVisible || mVpnVisible || mEthernetVisible;
setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
}
@@ -345,6 +384,7 @@ public class SignalClusterView
setTint(mAirplane, mIconTint);
applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
+ applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
for (int i = 0; i < mPhoneStates.size(); i++) {
mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
index 23810f9..ee5eb38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
@@ -25,4 +25,5 @@ import android.content.Intent;
*/
public interface ActivityStarter {
public void startActivity(Intent intent, boolean dismissShade);
+ void preventNextAnimation();
}
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..e6da81e 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);
@@ -64,11 +75,11 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mInitialTouchY = y;
mInitialTouchX = x;
setTrackingHeadsUp(false);
- ExpandableView child = mStackScroller.getChildAtPosition(x, y);
- mMotionOnHeadsUpView = false;
+ ExpandableView child = mStackScroller.getChildAtRawPosition(x, y);
+ 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:
@@ -84,20 +95,23 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
- if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)) {
+ if (mTouchingHeadsUpView && Math.abs(h) > mTouchSlop
+ && Math.abs(h) > Math.abs(x - mInitialTouchX)) {
setTrackingHeadsUp(true);
mCollapseSnoozes = h < 0;
mInitialTouchX = x;
mInitialTouchY = y;
int expandedHeight = mPickedChild.getActualHeight();
mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
+ mHeadsUpManager.unpinAll();
return true;
}
break;
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 +155,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/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 8343497..8bffdc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -131,6 +131,10 @@ public class KeyguardAffordanceHelper {
mCenterIcon = mCallback.getCenterIcon();
mRightIcon = mCallback.getRightIcon();
mRightIcon.setIsLeft(false);
+ updatePreviews();
+ }
+
+ public void updatePreviews() {
mLeftIcon.setPreviewView(mCallback.getLeftPreview());
mRightIcon.setPreviewView(mCallback.getRightPreview());
}
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..efc3ea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -25,17 +25,13 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
-import android.hardware.fingerprint.FingerprintManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.Vibrator;
import android.provider.MediaStore;
-import android.provider.Settings;
import android.telecom.TelecomManager;
import android.util.AttributeSet;
import android.util.Log;
@@ -54,6 +50,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -85,12 +82,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
private KeyguardAffordanceView mCameraImageView;
- private KeyguardAffordanceView mPhoneImageView;
- private KeyguardAffordanceView mLockIcon;
+ private KeyguardAffordanceView mLeftAffordanceView;
+ private LockIcon mLockIcon;
private TextView mIndicationText;
private ViewGroup mPreviewContainer;
- private View mPhonePreview;
+ private View mLeftPreview;
private View mCameraPreview;
private ActivityStarter mActivityStarter;
@@ -102,11 +99,10 @@ 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;
+ private boolean mLeftIsVoiceAssist;
+ private AssistManager mAssistManager;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -123,7 +119,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);
}
@@ -137,8 +132,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
label = getResources().getString(R.string.unlock_label);
} else if (host == mCameraImageView) {
label = getResources().getString(R.string.camera_label);
- } else if (host == mPhoneImageView) {
- label = getResources().getString(R.string.phone_label);
+ } else if (host == mLeftAffordanceView) {
+ if (mLeftIsVoiceAssist) {
+ label = getResources().getString(R.string.voice_assist_label);
+ } else {
+ label = getResources().getString(R.string.phone_label);
+ }
}
info.addAction(new AccessibilityAction(ACTION_CLICK, label));
}
@@ -153,8 +152,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
} else if (host == mCameraImageView) {
launchCamera();
return true;
- } else if (host == mPhoneImageView) {
- launchPhone();
+ } else if (host == mLeftAffordanceView) {
+ launchLeftAffordance();
return true;
}
}
@@ -168,30 +167,28 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLockPatternUtils = new LockPatternUtils(mContext);
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);
+ mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
+ 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();
+ inflateCameraPreview();
mLockIcon.setOnClickListener(this);
- mLockIcon.setBackground(mTrustDrawable);
mLockIcon.setOnLongClickListener(this);
mCameraImageView.setOnClickListener(this);
- mPhoneImageView.setOnClickListener(this);
+ mLeftAffordanceView.setOnClickListener(this);
initAccessibility();
}
private void initAccessibility() {
mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
- mPhoneImageView.setAccessibilityDelegate(mAccessibilityDelegate);
+ mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate);
mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate);
}
@@ -222,6 +219,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public void setAccessibilityController(AccessibilityController accessibilityController) {
mAccessibilityController = accessibilityController;
+ mLockIcon.setAccessibilityController(accessibilityController);
accessibilityController.addStateChangedCallback(this);
}
@@ -233,9 +231,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,15 +243,32 @@ 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);
}
- private void updatePhoneVisibility() {
- boolean visible = isPhoneVisible();
- mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
+ private void updateLeftAffordanceIcon() {
+ mLeftIsVoiceAssist = canLaunchVoiceAssist();
+ int drawableId;
+ int contentDescription;
+ if (mLeftIsVoiceAssist) {
+ mLeftAffordanceView.setVisibility(View.VISIBLE);
+ drawableId = R.drawable.ic_mic_26dp;
+ contentDescription = R.string.accessibility_voice_assist_button;
+ } else {
+ boolean visible = isPhoneVisible();
+ mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE);
+ drawableId = R.drawable.ic_phone_24dp;
+ contentDescription = R.string.accessibility_phone_button;
+ }
+ mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId));
+ mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription));
+ }
+
+ public boolean isLeftVoiceAssist() {
+ return mLeftIsVoiceAssist;
}
private boolean isPhoneVisible() {
@@ -291,32 +306,18 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) {
mCameraImageView.setClickable(touchExplorationEnabled);
- mPhoneImageView.setClickable(touchExplorationEnabled);
+ mLeftAffordanceView.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());
+ mLeftAffordanceView.setFocusable(accessibilityEnabled);
+ mLockIcon.update();
}
@Override
public void onClick(View v) {
if (v == mCameraImageView) {
launchCamera();
- } else if (v == mPhoneImageView) {
- launchPhone();
+ } else if (v == mLeftAffordanceView) {
+ launchLeftAffordance();
} if (v == mLockIcon) {
if (!mAccessibilityController.isAccessibilityEnabled()) {
handleTrustCircleClick();
@@ -339,13 +340,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 +362,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,12 +376,13 @@ 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
public void run() {
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ mActivityStarter.preventNextAnimation();
}
});
} else {
@@ -391,7 +393,35 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
}
- public void launchPhone() {
+ public void launchLeftAffordance() {
+ if (mLeftIsVoiceAssist) {
+ launchVoiceAssist();
+ } else {
+ launchPhone();
+ }
+ }
+
+ private void launchVoiceAssist() {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ mAssistManager.launchVoiceAssistFromKeyguard();
+ mActivityStarter.preventNextAnimation();
+ }
+ };
+ if (mPhoneStatusBar.isKeyguardCurrentlySecure()) {
+ AsyncTask.execute(runnable);
+ } else {
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, false /* dismissShade */,
+ false /* afterKeyguardGone */);
+ }
+ }
+
+ private boolean canLaunchVoiceAssist() {
+ return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard();
+ }
+
+ private void launchPhone() {
final TelecomManager tm = TelecomManager.from(mContext);
if (tm.isInCall()) {
AsyncTask.execute(new Runnable() {
@@ -409,82 +439,25 @@ 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;
+ public KeyguardAffordanceView getLeftView() {
+ return mLeftAffordanceView;
}
- public KeyguardAffordanceView getCameraView() {
+ public KeyguardAffordanceView getRightView() {
return mCameraImageView;
}
- public View getPhonePreview() {
- return mPhonePreview;
+ public View getLeftPreview() {
+ return mLeftPreview;
}
- public View getCameraPreview() {
+ public View getRightPreview() {
return mCameraPreview;
}
@@ -503,27 +476,39 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
@Override
public void onUnlockMethodStateChanged() {
- updateLockIcon();
+ mLockIcon.update();
updateCameraVisibility();
}
- private void inflatePreviews() {
- mPhonePreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
+ private void inflateCameraPreview() {
mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent());
- if (mPhonePreview != null) {
- mPreviewContainer.addView(mPhonePreview);
- mPhonePreview.setVisibility(View.INVISIBLE);
- }
if (mCameraPreview != null) {
mPreviewContainer.addView(mCameraPreview);
mCameraPreview.setVisibility(View.INVISIBLE);
}
}
+ private void updateLeftPreview() {
+ View previewBefore = mLeftPreview;
+ if (previewBefore != null) {
+ mPreviewContainer.removeView(previewBefore);
+ }
+ if (mLeftIsVoiceAssist) {
+ mLeftPreview = mPreviewInflater.inflatePreviewFromService(
+ mAssistManager.getVoiceInteractorComponentName());
+ } else {
+ mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT);
+ }
+ if (mLeftPreview != null) {
+ mPreviewContainer.addView(mLeftPreview);
+ mLeftPreview.setVisibility(View.INVISIBLE);
+ }
+ }
+
public void startFinishDozeAnimation() {
long delay = 0;
- if (mPhoneImageView.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mPhoneImageView, delay);
+ if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
+ startFinishDozeAnimationElement(mLeftAffordanceView, delay);
delay += DOZE_ANIMATION_STAGGER_DELAY;
}
startFinishDozeAnimationElement(mLockIcon, delay);
@@ -563,9 +548,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 +562,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 +581,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();
}
};
@@ -623,28 +604,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
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;
- }
+ public void setAssistManager(AssistManager assistManager) {
+ mAssistManager = assistManager;
+ updateLeftAffordance();
+ }
- @Override
- public int getIntrinsicHeight() {
- return mIntrinsicHeight;
- }
+ public void updateLeftAffordance() {
+ updateLeftAffordanceIcon();
+ updateLeftPreview();
}
}
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/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index c62ad66..7077a17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -144,7 +144,7 @@ public class NavigationBarView extends LinearLayout {
@Override
public void onClick(View view) {
((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE))
- .showInputMethodPicker();
+ .showInputMethodPicker(true /* showAuxiliarySubtypes */);
}
};
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..9ef9211 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,6 +39,7 @@ import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
@@ -73,6 +74,10 @@ public class NotificationPanelView extends PanelView implements
private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
+ private static final String COUNTER_PANEL_OPEN = "panel_open";
+ private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
+ private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
+
public static final long DOZE_ANIMATION_DURATION = 700;
private KeyguardAffordanceHelper mAfforanceHelper;
@@ -182,11 +187,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 +332,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 +539,18 @@ 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;
+ MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
+ MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
return true;
}
- if (!isShadeCollapsed() && onQsIntercept(event)) {
+ if (!isFullyCollapsed() && onQsIntercept(event)) {
return true;
}
return super.onInterceptTouchEvent(event);
@@ -618,7 +624,7 @@ public class NotificationPanelView extends PanelView implements
case MotionEvent.ACTION_UP:
trackMovement(event);
if (mQsTracking) {
- flingQsWithCurrentVelocity(
+ flingQsWithCurrentVelocity(y,
event.getActionMasked() == MotionEvent.ACTION_CANCEL);
mQsTracking = false;
}
@@ -641,6 +647,7 @@ public class NotificationPanelView extends PanelView implements
mOnlyAffordanceInThisMotion = false;
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
mDozingOnDown = isDozing();
+ mCollapsedOnDown = isFullyCollapsed();
}
}
@@ -655,9 +662,24 @@ public class NotificationPanelView extends PanelView implements
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
- private void flingQsWithCurrentVelocity(boolean isCancelMotionEvent) {
+ private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
+ float vel = getCurrentVelocity();
+ final boolean expandsQs = flingExpandsQs(vel);
+ if (expandsQs) {
+ logQsSwipeDown(y);
+ }
+ flingSettings(vel, expandsQs && !isCancelMotionEvent);
+ }
+
+ private void logQsSwipeDown(float y) {
float vel = getCurrentVelocity();
- flingSettings(vel, flingExpandsQs(vel) && !isCancelMotionEvent);
+ final int gesture = mStatusBarState == StatusBarState.KEYGUARD
+ ? EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS
+ : EventLogConstants.SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS;
+ EventLogTags.writeSysuiLockscreenGesture(
+ gesture,
+ (int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()),
+ (int) (vel / mStatusBar.getDisplayDensity()));
}
private boolean flingExpandsQs(float vel) {
@@ -695,18 +717,20 @@ 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()) {
+ MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
updateVerticalPanelPosition(event.getX());
}
super.onTouchEvent(event);
return true;
}
- private boolean handleQSTouch(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
+ private boolean handleQsTouch(MotionEvent event) {
+ final int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
&& mStatusBar.getBarState() != StatusBarState.KEYGUARD && !mQsExpanded
&& mQsExpansionEnabled) {
@@ -718,7 +742,7 @@ public class NotificationPanelView extends PanelView implements
mInitialTouchY = event.getX();
mInitialTouchX = event.getY();
}
- if (!isShadeCollapsed()) {
+ if (!isFullyCollapsed()) {
handleQsDown(event);
}
if (!mQsExpandImmediate && mQsTracking) {
@@ -727,17 +751,23 @@ public class NotificationPanelView extends PanelView implements
return true;
}
}
- if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
- || event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mConflictingQsExpansionGesture = false;
}
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isShadeCollapsed()
+ if (action == MotionEvent.ACTION_DOWN && isFullyCollapsed()
&& mQsExpansionEnabled) {
mTwoFingerQsExpandPossible = true;
}
- if (mTwoFingerQsExpandPossible && event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
- && event.getPointerCount() == 2
+ final int pointerCount = event.getPointerCount();
+ final boolean twoFingerDrag = action == MotionEvent.ACTION_POINTER_DOWN
+ && pointerCount == 2;
+ final boolean stylusClickDrag = action == MotionEvent.ACTION_DOWN
+ && pointerCount == 1 && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+ && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
+ || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+ if (mTwoFingerQsExpandPossible && (twoFingerDrag || stylusClickDrag)
&& event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
+ MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
mQsExpandImmediate = true;
requestPanelHeightUpdate();
@@ -799,6 +829,7 @@ public class NotificationPanelView extends PanelView implements
}
final float y = event.getY(pointerIndex);
final float x = event.getX(pointerIndex);
+ final float h = y - mInitialTouchY;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
@@ -826,7 +857,6 @@ public class NotificationPanelView extends PanelView implements
break;
case MotionEvent.ACTION_MOVE:
- final float h = y - mInitialTouchY;
setQsExpansion(h + mInitialHeightOnTouch);
if (h >= getFalsingThreshold()) {
mQsTouchAboveFalsingThreshold = true;
@@ -842,9 +872,10 @@ public class NotificationPanelView extends PanelView implements
float fraction = getQsExpansionFraction();
if ((fraction != 0f || y >= mInitialTouchY)
&& (fraction != 1f || y <= mInitialTouchY)) {
- flingQsWithCurrentVelocity(
+ flingQsWithCurrentVelocity(y,
event.getActionMasked() == MotionEvent.ACTION_CANCEL);
} else {
+ logQsSwipeDown(y);
mScrollYOverride = -1;
}
if (mVelocityTracker != null) {
@@ -952,6 +983,10 @@ public class NotificationPanelView extends PanelView implements
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
+ if (keyguardShowing && oldState != mStatusBarState) {
+ mKeyguardBottomArea.updateLeftAffordance();
+ mAfforanceHelper.updatePreviews();
+ }
}
resetVerticalPanelPosition();
updateQsState();
@@ -1191,8 +1226,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 +1421,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 +1492,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 +1570,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 +1648,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 +1716,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 +1826,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
@@ -1817,6 +1850,9 @@ public class NotificationPanelView extends PanelView implements
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */);
} else if (mQsExpansionEnabled) {
+ EventLogTags.writeSysuiLockscreenGesture(
+ EventLogConstants.SYSUI_TAP_TO_OPEN_QS,
+ 0, 0);
flingSettings(0 /* vel */, true /* expand */);
}
}
@@ -1833,7 +1869,7 @@ public class NotificationPanelView extends PanelView implements
if (start) {
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
- mKeyguardBottomArea.launchPhone();
+ mKeyguardBottomArea.launchLeftAffordance();
} else {
EventLogTags.writeSysuiLockscreenGesture(
EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
@@ -1914,15 +1950,19 @@ public class NotificationPanelView extends PanelView implements
if (rightIcon) {
mStatusBar.onCameraHintStarted();
} else {
- mStatusBar.onPhoneHintStarted();
+ if (mKeyguardBottomArea.isLeftVoiceAssist()) {
+ mStatusBar.onVoiceAssistHintStarted();
+ } else {
+ mStatusBar.onPhoneHintStarted();
+ }
}
}
@Override
public KeyguardAffordanceView getLeftIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getCameraView()
- : mKeyguardBottomArea.getPhoneView();
+ ? mKeyguardBottomArea.getRightView()
+ : mKeyguardBottomArea.getLeftView();
}
@Override
@@ -1933,22 +1973,22 @@ public class NotificationPanelView extends PanelView implements
@Override
public KeyguardAffordanceView getRightIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getPhoneView()
- : mKeyguardBottomArea.getCameraView();
+ ? mKeyguardBottomArea.getLeftView()
+ : mKeyguardBottomArea.getRightView();
}
@Override
public View getLeftPreview() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getCameraPreview()
- : mKeyguardBottomArea.getPhonePreview();
+ ? mKeyguardBottomArea.getRightPreview()
+ : mKeyguardBottomArea.getLeftPreview();
}
@Override
public View getRightPreview() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getPhonePreview()
- : mKeyguardBottomArea.getCameraPreview();
+ ? mKeyguardBottomArea.getLeftPreview()
+ : mKeyguardBottomArea.getRightPreview();
}
@Override
@@ -2160,48 +2200,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 +2276,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/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index f3d4c7f..d5209ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -80,6 +80,14 @@ public class PanelBar extends FrameLayout {
}
}
+ public void setBouncerShowing(boolean showing) {
+ if (mPanelHolder != null) {
+ mPanelHolder.setImportantForAccessibility(
+ showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
+ }
+
public float getBarHeight() {
return getMeasuredHeight();
}
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..38812ce 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,14 @@ 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;
@@ -77,6 +78,7 @@ public abstract class PanelView extends FrameLayout {
private boolean mTouchStartedInEmptyArea;
private boolean mMotionAborted;
private boolean mUpwardsWhenTresholdReached;
+ private boolean mAnimatingOnDown;
private ValueAnimator mHeightAnimator;
private ObjectAnimator mPeekAnimator;
@@ -242,15 +244,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 +270,7 @@ public abstract class PanelView extends FrameLayout {
|| mPeekPending || mPeekAnimator != null;
onTrackingStarted();
}
- if (isShadeCollapsed()) {
+ if (isFullyCollapsed()) {
schedulePeek();
}
break;
@@ -459,8 +461,8 @@ public abstract class PanelView extends FrameLayout {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mStatusBar.userActivity();
- if (mHeightAnimator != null && !mHintAnimationRunning ||
- mPeekPending || mPeekAnimator != null) {
+ mAnimatingOnDown = mHeightAnimator != null;
+ if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) {
cancelHeightAnimator();
cancelPeek();
mTouchSlopExceeded = true;
@@ -472,7 +474,7 @@ public abstract class PanelView extends FrameLayout {
mTouchSlopExceeded = false;
mJustPeeked = false;
mMotionAborted = false;
- mPanelClosedOnDown = isShadeCollapsed();
+ mPanelClosedOnDown = isFullyCollapsed();
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mTouchAboveFalsingThreshold = false;
@@ -501,8 +503,10 @@ public abstract class PanelView extends FrameLayout {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
trackMovement(event);
- if (scrolledToBottom || mTouchStartedInEmptyArea) {
- if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) {
+ if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) {
+ float hAbs = Math.abs(h);
+ if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop))
+ && hAbs > Math.abs(x - mInitialTouchX)) {
cancelHeightAnimator();
startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
return true;
@@ -707,7 +711,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 +1061,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..887b8f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -76,8 +76,10 @@ import android.view.Display;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.ThreadedRenderer;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewStub;
import android.view.WindowManager;
@@ -91,6 +93,7 @@ import android.view.animation.PathInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.ViewMediatorCallback;
@@ -100,7 +103,7 @@ import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.assist.AssistGestureManager;
+import com.android.systemui.assist.AssistManager;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -297,7 +300,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
int mTrackingPosition; // the position of the top of the tracking view.
// Tracking finger for opening/closing.
- int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
boolean mTracking;
VelocityTracker mVelocityTracker;
@@ -311,6 +313,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// tracking calls to View.setSystemUiVisibility()
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ // last value sent to window manager
+ private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
+
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
// XXX: gesture research
@@ -323,7 +328,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mNavigationIconHints = 0;
private HandlerThread mHandlerThread;
- private AssistGestureManager mAssistGestureManager;
+ private AssistManager mAssistManager;
// ensure quick settings is disabled until the current user makes it through the setup wizard
private boolean mUserSetup = false;
@@ -528,6 +533,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
= new HashMap<>();
private HashSet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new HashSet<>();
private RankingMap mLatestRankingMap;
+ private boolean mNoAnimationOnNextBarModeChange;
@Override
public void start() {
@@ -617,7 +623,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
R.color.notification_panel_solid_background)));
}
- mHeadsUpManager = new HeadsUpManager(context, mNotificationPanel.getViewTreeObserver());
+ mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
mHeadsUpManager.setBar(this);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanel);
@@ -645,8 +651,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
new NavigationBarView.OnVerticalChangedListener() {
@Override
public void onVerticalChanged(boolean isVertical) {
- if (mAssistGestureManager != null) {
- mAssistGestureManager.onConfigurationChanged();
+ if (mAssistManager != null) {
+ mAssistManager.onConfigurationChanged();
}
mNotificationPanel.setQsScrimEnabled(!isVertical);
}
@@ -662,6 +668,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// no window manager? good luck with that
}
+ mAssistManager = new AssistManager(this, context);
+
// figure out which pixel-format to use for the status bar.
mPixelFormat = PixelFormat.OPAQUE;
@@ -691,6 +699,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mDismissView.setOnButtonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
clearAllNotifications();
}
});
@@ -719,13 +728,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardBottomArea =
(KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
mKeyguardBottomArea.setActivityStarter(this);
+ mKeyguardBottomArea.setAssistManager(mAssistManager);
mKeyguardIndicationController = new KeyguardIndicationController(mContext,
(KeyguardIndicationTextView) mStatusBarWindow.findViewById(
R.id.keyguard_indication_text));
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
// set the inital view visibility
setAreThereNotifications();
@@ -752,7 +760,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// noop
}
});
- mNetworkController = new NetworkControllerImpl(mContext);
+ mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
mHotspotController = new HotspotControllerImpl(mContext);
mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
mSecurityController = new SecurityControllerImpl(mContext);
@@ -842,7 +850,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mBroadcastReceiver.onReceive(mContext,
new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
- mAssistGestureManager = new AssistGestureManager(this, context);
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -858,6 +865,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// listen for USER_SETUP_COMPLETE setting (per-user)
resetUserSetupObserver();
+ // disable profiling bars, since they overlap and clutter the output on app windows
+ ThreadedRenderer.overrideProperty("disableProfileBars", "true");
+
+ // Private API call to make the shadows look better for Recents
+ ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
+
return mStatusBarView;
}
@@ -965,7 +978,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void invokeAssistGesture(boolean vibrate) {
mHandler.removeCallbacks(mInvokeAssist);
- mAssistGestureManager.onGestureInvoked(vibrate);
+ mAssistManager.onGestureInvoked(vibrate);
}
public int getStatusBarHeight() {
@@ -1045,7 +1058,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNavigationBarView.getBackButton().setLongClickable(true);
mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
- mAssistGestureManager.onConfigurationChanged();
+ mAssistManager.onConfigurationChanged();
}
// For small-screen devices (read: phones) that lack hardware navigation buttons
@@ -1152,11 +1165,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;
@@ -1185,8 +1198,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void updateShowSearchHoldoff() {
- mShowSearchHoldoff = mContext.getResources().getInteger(
- R.integer.config_show_search_delay);
+ mShowSearchHoldoff = ViewConfiguration.getLongPressTimeout();
}
private void updateNotificationShade() {
@@ -1293,13 +1305,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() {
@@ -1583,9 +1602,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
- + " metadata=" + mMediaMetadata
- + " metaDataChanged=" + metaDataChanged
- + " state=" + mState);
+ + " metadata=" + mMediaMetadata
+ + " metaDataChanged=" + metaDataChanged
+ + " state=" + mState);
}
Bitmap artworkBitmap = null;
@@ -1694,6 +1713,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
* State is one or more of the DISABLE constants from StatusBarManager.
*/
public void disable(int state1, int state2, boolean animate) {
+ animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
mDisabledUnmodified1 = state1;
mDisabledUnmodified2 = state2;
state1 = adjustDisableFlags(state1);
@@ -1732,6 +1752,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 +1803,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
@@ -1792,6 +1819,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
startActivityDismissingKeyguard(intent, false, dismissShade);
}
+ @Override
+ public void preventNextAnimation() {
+ overrideActivityPendingAppTransition(true /* keyguardShowing */);
+ }
+
public void setQsExpanded(boolean expanded) {
mStatusBarWindowManager.setQsExpanded(expanded);
}
@@ -1838,32 +1870,57 @@ 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() {
- @Override
- public void run() {
- if (!mHeadsUpManager.hasPinnedHeadsUp()) {
- mStatusBarWindowManager.setHeadsUpShowing(false);
+ mStatusBarWindowManager.setForceStatusBarVisible(true);
+ if (mNotificationPanel.isFullyCollapsed()) {
+ // We need to ensure that the touchable region is updated before the window will be
+ // resized, in order to not catch any touches. A layout will ensure that
+ // onComputeInternalInsets will be called and after that we can resize the layout. Let's
+ // make sure that the window stays small for one frame until the touchableRegion is set.
+ mNotificationPanel.requestLayout();
+ mStatusBarWindowManager.setForceWindowCollapsed(true);
+ mNotificationPanel.post(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setForceWindowCollapsed(false);
}
- }
- };
- if (changeImmediatly) {
- endRunnable.run();
+ });
+ }
+ } else {
+ if (!mNotificationPanel.isFullyCollapsed() || mNotificationPanel.isTracking()) {
+ // We are currently tracking or is open and the shade doesn't need to be kept
+ // open artificially.
+ mStatusBarWindowManager.setHeadsUpShowing(false);
} else {
- mStackScroller.performOnAnimationFinished(endRunnable);
+ // we need to keep the panel open artificially, let's wait until the animation
+ // is finished.
+ mHeadsUpManager.setHeadsUpGoingAway(true);
+ mStackScroller.runAfterAnimationFinished(new Runnable() {
+ @Override
+ public void run() {
+ if (!mHeadsUpManager.hasPinnedHeadsUp()) {
+ mStatusBarWindowManager.setHeadsUpShowing(false);
+ mHeadsUpManager.setHeadsUpGoingAway(false);
+ }
+ }
+ });
}
}
}
@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 +1937,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!
@@ -1905,6 +1963,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
+ public boolean isKeyguardCurrentlySecure() {
+ return !mUnlockMethodCache.isCurrentlyInsecure();
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
@@ -1929,7 +1991,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;
@@ -2095,6 +2157,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Shrink the window to the size of the status bar only
mStatusBarWindowManager.setStatusBarExpanded(false);
+ mStatusBarWindowManager.setForceStatusBarVisible(false);
mStatusBarView.setFocusable(true);
// Close any "App info" popups that might have snuck on-screen
@@ -2235,6 +2298,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
setAreThereNotifications();
}
+ // ready to unhide
+ if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
+ mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+ mNoAnimationOnNextBarModeChange = true;
+ }
+
// update status bar mode
final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(),
View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT);
@@ -2266,10 +2335,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
- // ready to unhide
- if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
- mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
- }
if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
@@ -2314,17 +2379,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void checkBarModes() {
if (mDemoMode) return;
- checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
+ checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions(),
+ mNoAnimationOnNextBarModeChange);
if (mNavigationBarView != null) {
checkBarMode(mNavigationBarMode,
- mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
+ mNavigationBarWindowState, mNavigationBarView.getBarTransitions(),
+ mNoAnimationOnNextBarModeChange);
}
+ mNoAnimationOnNextBarModeChange = false;
}
- private void checkBarMode(int mode, int windowState, BarTransitions transitions) {
+ private void checkBarMode(int mode, int windowState, BarTransitions transitions,
+ boolean noAnimation) {
final boolean powerSave = mBatteryController.isPowerSave();
- final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN
- && !powerSave;
+ final boolean anim = !noAnimation && (mScreenOn == null || mScreenOn)
+ && windowState != WINDOW_STATE_HIDDEN && !powerSave;
if (powerSave && getBarState() == StatusBarState.SHADE) {
mode = MODE_WARNING;
}
@@ -2358,13 +2427,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();
@@ -2417,7 +2490,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void notifyUiVisibilityChanged(int vis) {
try {
- mWindowManagerService.statusBarVisibilityChanged(vis);
+ if (mLastDispatchedSystemUiVisibility != vis) {
+ mWindowManagerService.statusBarVisibilityChanged(vis);
+ mLastDispatchedSystemUiVisibility = vis;
+ }
} catch (RemoteException ex) {
}
}
@@ -2627,6 +2703,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, mCurrentUserId);
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
+ Runnable runnable = new Runnable() {
+ public void run() {
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivityAsUser(
+ intent, new UserHandle(UserHandle.USER_CURRENT));
+ overrideActivityPendingAppTransition(
+ keyguardShowing && !afterKeyguardGone);
+ }
+ };
+ executeRunnableDismissingKeyguard(runnable, dismissShade, afterKeyguardGone);
+ }
+
+ public void executeRunnableDismissingKeyguard(final Runnable runnable,
+ final boolean dismissShade,
+ final boolean afterKeyguardGone) {
+ final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
public boolean onDismiss() {
@@ -2637,12 +2730,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
ActivityManagerNative.getDefault()
.keyguardWaitingForActivityDrawn();
}
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivityAsUser(
- intent, new UserHandle(UserHandle.USER_CURRENT));
- overrideActivityPendingAppTransition(
- keyguardShowing && !afterKeyguardGone);
+ if (runnable != null) {
+ runnable.run();
+ }
} catch (RemoteException e) {
}
}
@@ -2794,8 +2884,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNaturalBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
@@ -2852,6 +2940,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} catch (RemoteException e) {
// Ignore.
}
+ setNotificationsShown(newlyVisibleAr);
}
// State logging
@@ -2997,7 +3086,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mHandlerThread = null;
}
mContext.unregisterReceiver(mBroadcastReceiver);
- mAssistGestureManager.destroy();
+ mAssistManager.destroy();
}
private boolean mDemoModeAllowed;
@@ -3445,6 +3534,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
}
+ public void onVoiceAssistHintStarted() {
+ mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
+ }
+
public void onPhoneHintStarted() {
mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
}
@@ -3557,6 +3650,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void setBouncerShowing(boolean bouncerShowing) {
super.setBouncerShowing(bouncerShowing);
+ mStatusBarView.setBouncerShowing(bouncerShowing);
disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
}
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..5942b46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -219,19 +219,20 @@ public class PhoneStatusBarPolicy {
if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
zenVisible = mZen != Global.ZEN_MODE_OFF;
- zenIconId = R.drawable.stat_sys_dnd;
+ zenIconId = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS
+ ? R.drawable.stat_sys_dnd_total_silence : R.drawable.stat_sys_dnd;
zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
} 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/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 954eb10..0ef0fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -67,11 +67,12 @@ public class QSTileHost implements QSTile.Host {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String TILES_SETTING = "sysui_qs_tiles";
+ protected static final String TILES_SETTING = "sysui_qs_tiles";
private final Context mContext;
private final PhoneStatusBar mStatusBar;
private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
+ private final ArrayList<String> mTileSpecs = new ArrayList<>();
private final Observer mObserver = new Observer();
private final BluetoothController mBluetooth;
private final LocationController mLocation;
@@ -81,7 +82,7 @@ public class QSTileHost implements QSTile.Host {
private final HotspotController mHotspot;
private final CastController mCast;
private final Looper mLooper;
- private final CurrentUserTracker mUserTracker;
+ protected final CurrentUserTracker mUserTracker;
private final FlashlightController mFlashlight;
private final UserSwitcherController mUserSwitcherController;
private final KeyguardMonitor mKeyguard;
@@ -224,6 +225,7 @@ public class QSTileHost implements QSTile.Host {
private void recreateTiles() {
if (DEBUG) Log.d(TAG, "Recreating tiles");
final List<String> tileSpecs = loadTileSpecs();
+ if (tileSpecs.equals(mTileSpecs)) return;
for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) {
if (!tileSpecs.contains(tile.getKey())) {
if (DEBUG) Log.d(TAG, "Destroying tile: " + tile.getKey());
@@ -243,7 +245,8 @@ public class QSTileHost implements QSTile.Host {
}
}
}
- if (mTiles.equals(newTiles)) return;
+ mTileSpecs.clear();
+ mTileSpecs.addAll(tileSpecs);
mTiles.clear();
mTiles.putAll(newTiles);
if (mCallback != null) {
@@ -251,7 +254,7 @@ public class QSTileHost implements QSTile.Host {
}
}
- private QSTile<?> createTile(String tileSpec) {
+ protected QSTile<?> createTile(String tileSpec) {
if (tileSpec.equals("wifi")) return new WifiTile(this);
else if (tileSpec.equals("bt")) return new BluetoothTile(this);
else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
@@ -267,7 +270,7 @@ public class QSTileHost implements QSTile.Host {
else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
}
- private List<String> loadTileSpecs() {
+ protected List<String> loadTileSpecs() {
final Resources res = mContext.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
String tileList = Secure.getStringForUser(mContext.getContentResolver(), TILES_SETTING,
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..808f1ff 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;
@@ -115,6 +115,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
if (mFraction != fraction) {
mFraction = fraction;
scheduleUpdate();
+ if (mPinnedHeadsUpCount != 0) {
+ updateHeadsUpScrim(false);
+ }
}
}
@@ -347,25 +350,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 +379,11 @@ 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();
+ } else {
+ animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim, TAG_HUN_END_ALPHA);
}
- animEndValue = StackStateAnimator.getChildTag(mHeadsUpScrim,
- TAG_HUN_START_ALPHA);
}
if (alpha != mCurrentHeadsUpAlpha && alpha != animEndValue) {
if (animate) {
@@ -390,7 +394,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 +414,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,12 +428,16 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
}
private float calculateHeadsUpAlpha() {
- if (mAmountOfPinnedHeadsUps >= 2) {
- return 1.0f;
- } else if (mAmountOfPinnedHeadsUps == 0) {
- return 0.0f;
+ float alpha;
+ if (mPinnedHeadsUpCount >= 2) {
+ alpha = 1.0f;
+ } else if (mPinnedHeadsUpCount == 0) {
+ alpha = 0.0f;
} else {
- return 1.0f - mTopHeadsUpDragAmount;
+ alpha = 1.0f - mTopHeadsUpDragAmount;
}
+ float expandFactor = (1.0f - mFraction);
+ expandFactor = Math.max(expandFactor, 0.0f);
+ return alpha * expandFactor;
}
}
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/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 84a9f64..422d868 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -129,8 +129,9 @@ public class StatusBarWindowManager {
}
private void applyHeight(State state) {
- boolean expanded = state.isKeyguardShowingAndNotOccluded() || state.statusBarExpanded
- || state.keyguardFadingAway || state.bouncerShowing || state.headsUpShowing;
+ boolean expanded = !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
+ || state.statusBarExpanded || state.keyguardFadingAway || state.bouncerShowing
+ || state.headsUpShowing);
if (expanded) {
mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
@@ -166,6 +167,7 @@ public class StatusBarWindowManager {
private void apply(State state) {
applyKeyguardFlags(state);
+ applyForceStatusBarVisibleFlag(state);
applyFocusableFlag(state);
adjustScreenOrientation(state);
applyHeight(state);
@@ -178,6 +180,16 @@ public class StatusBarWindowManager {
}
}
+ private void applyForceStatusBarVisibleFlag(State state) {
+ if (state.forceStatusBarVisible) {
+ mLpChanged.privateFlags |= WindowManager
+ .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+ } else {
+ mLpChanged.privateFlags &= ~WindowManager
+ .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+ }
+ }
+
private void applyModalFlag(State state) {
if (state.headsUpShowing) {
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -240,6 +252,21 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ public void setForceStatusBarVisible(boolean forceStatusBarVisible) {
+ mCurrentState.forceStatusBarVisible = forceStatusBarVisible;
+ apply(mCurrentState);
+ }
+
+ /**
+ * Force the window to be collapsed, even if it should theoretically be expanded.
+ * Used for when a heads-up comes in but we still need to wait for the touchable regions to
+ * be computed.
+ */
+ public void setForceWindowCollapsed(boolean force) {
+ mCurrentState.forceCollapsed = force;
+ apply(mCurrentState);
+ }
+
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
@@ -250,6 +277,8 @@ public class StatusBarWindowManager {
boolean keyguardFadingAway;
boolean qsExpanded;
boolean headsUpShowing;
+ boolean forceStatusBarVisible;
+ boolean forceCollapsed;
/**
* The {@link BaseStatusBar} state from the status bar.
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/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 18983ff..5893cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager.ActionListener;
+import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -58,10 +59,10 @@ public class AccessPointControllerImpl
private int mCurrentUser;
- public AccessPointControllerImpl(Context context) {
+ public AccessPointControllerImpl(Context context, Looper bgLooper) {
mContext = context;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mWifiTracker = new WifiTracker(context, this, false, true);
+ mWifiTracker = new WifiTracker(context, this, bgLooper, false, true);
mCurrentUser = ActivityManager.getCurrentUser();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
index 63fcbc5..8f86e2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityContentDescriptions.java
@@ -35,4 +35,9 @@ public class AccessibilityContentDescriptions {
};
static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;
+
+ static final int[] ETHERNET_CONNECTION_VALUES = {
+ R.string.accessibility_ethernet_disconnected,
+ R.string.accessibility_ethernet_connected,
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java
new file mode 100644
index 0000000..b391bd9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java
@@ -0,0 +1,26 @@
+/*
+ * 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.policy;
+
+import com.android.systemui.R;
+
+class EthernetIcons {
+ static final int[][] ETHERNET_ICONS = {
+ { R.drawable.stat_sys_ethernet },
+ { R.drawable.stat_sys_ethernet_fully },
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
new file mode 100644
index 0000000..9c044c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
@@ -0,0 +1,68 @@
+/*
+ * 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.policy;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
+
+import java.util.List;
+import java.util.Objects;
+
+
+public class EthernetSignalController extends
+ SignalController<SignalController.State, SignalController.IconGroup> {
+
+ public EthernetSignalController(Context context,
+ List<NetworkSignalChangedCallback> signalCallbacks,
+ List<SignalCluster> signalClusters, NetworkControllerImpl networkController) {
+ super("EthernetSignalController", context, NetworkCapabilities.TRANSPORT_ETHERNET,
+ signalCallbacks, signalClusters, networkController);
+ mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
+ "Ethernet Icons",
+ EthernetIcons.ETHERNET_ICONS,
+ null,
+ AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES,
+ 0, 0, 0, 0,
+ AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[0]);
+ }
+
+ @Override
+ public void notifyListeners() {
+ boolean ethernetVisible = mCurrentState.connected;
+ String contentDescription = getStringIfExists(getContentDescription());
+
+ // TODO: wire up data transfer using WifiSignalPoller.
+ int signalClustersLength = mSignalClusters.size();
+ for (int i = 0; i < signalClustersLength; i++) {
+ mSignalClusters.get(i).setEthernetIndicators(ethernetVisible, getCurrentIconId(),
+ contentDescription);
+ }
+ }
+
+ @Override
+ public SignalController.State cleanState() {
+ return new SignalController.State();
+ }
+
+ public void setConnected(boolean connected) {
+ mCurrentState.connected = connected;
+ notifyListenersIfNecessary();
+ }
+}
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..14060df 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.
@@ -25,6 +25,7 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pools;
+import android.view.View;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
@@ -35,11 +36,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 +54,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 +73,14 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
@Override
public boolean release(HeadsUpEntry instance) {
- instance.removeAutoCancelCallbacks();
+ instance.reset();
mPoolObjects.push(instance);
return true;
}
};
-
+ private final View mStatusBarWindowView;
+ private final int mStatusBarHeight;
private PhoneStatusBar mBar;
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
@@ -86,13 +93,15 @@ 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];
+ private boolean mHeadsUpGoingAway;
+ private boolean mWaitingOnCollapseWhenGoingAway;
+ private boolean mIsObserving;
- public HeadsUpManager(final Context context, ViewTreeObserver observer) {
+ public HeadsUpManager(final Context context, View statusBarWindowView) {
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,8 +125,24 @@ 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);
+ mStatusBarWindowView = statusBarWindowView;
+ mStatusBarHeight = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ }
+
+ private void updateTouchableRegionListener() {
+ boolean shouldObserve = mHasPinnedNotification || mHeadsUpGoingAway
+ || mWaitingOnCollapseWhenGoingAway;
+ if (shouldObserve == mIsObserving) {
+ return;
+ }
+ if (shouldObserve) {
+ mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ mStatusBarWindowView.requestLayout();
+ } else {
+ mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ }
+ mIsObserving = shouldObserve;
}
public void setBar(PhoneStatusBar bar) {
@@ -154,7 +179,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, shouldHeadsUpBecomePinned(headsUp));
}
}
@@ -165,22 +190,31 @@ 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, shouldHeadsUpBecomePinned(entry));
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 boolean shouldHeadsUpBecomePinned(NotificationData.Entry entry) {
+ return !mIsExpanded || hasFullScreenIntent(entry);
+ }
+
+ private boolean hasFullScreenIntent(NotificationData.Entry entry) {
+ return entry.notification.getNotification().fullScreenIntent != null;
+ }
+
+ 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 +223,24 @@ 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;
+ updateTouchableRegionListener();
+ for (OnHeadsUpChangedListener listener : mListeners) {
+ listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
}
}
@@ -222,7 +256,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
releaseImmediately(key);
return true;
} else {
- getHeadsUpEntry(key).hideAsSoonAsPossible();
+ getHeadsUpEntry(key).removeAsSoonAsPossible();
return false;
}
}
@@ -245,14 +279,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 +313,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 +343,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 +358,18 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
}
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- if (!mIsExpanded && mHasPinnedHeadsUp) {
+ if (mIsExpanded) {
+ // The touchable region is always the full area when expanded
+ return;
+ }
+ if (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);
@@ -340,6 +380,9 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(minX, minY, maxX, maxY);
+ } else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
+ info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
}
}
@@ -349,7 +392,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 +408,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 +457,10 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
if (isExpanded) {
- releaseAllToShade();
+ // make sure our state is sane
+ mWaitingOnCollapseWhenGoingAway = false;
+ mHeadsUpGoingAway = false;
+ updateTouchableRegionListener();
}
}
}
@@ -430,6 +470,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 +485,45 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
return aEntry.compareTo(bEntry);
}
+ /**
+ * Set that we are exiting the headsUp pinned mode, but some notifications might still be
+ * animating out. This is used to keep the touchable regions in a sane state.
+ */
+ public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+ if (headsUpGoingAway != mHeadsUpGoingAway) {
+ mHeadsUpGoingAway = headsUpGoingAway;
+ if (!headsUpGoingAway) {
+ waitForStatusBarLayout();
+ }
+ updateTouchableRegionListener();
+ }
+ }
+
+ /**
+ * We need to wait on the whole panel to collapse, before we can remove the touchable region
+ * listener.
+ */
+ private void waitForStatusBarLayout() {
+ mWaitingOnCollapseWhenGoingAway = true;
+ mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
+ mStatusBarWindowView.removeOnLayoutChangeListener(this);
+ mWaitingOnCollapseWhenGoingAway = false;
+ updateTouchableRegionListener();
+ }
+ }
+ });
+ }
+
+
+ /**
+ * 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 +534,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,8 +552,8 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
long currentTime = mClock.currentTimeMillis();
earliestRemovaltime = currentTime + mMinimumDisplayTime;
postTime = Math.max(postTime, currentTime);
- removeAutoCancelCallbacks();
- if (canEntryDecay()) {
+ removeAutoRemovalCallbacks();
+ if (!hasFullScreenIntent(entry)) {
long finishTime = postTime + mHeadsUpNotificationDecay;
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
@@ -476,10 +561,6 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
updateSortOrder(HeadsUpEntry.this);
}
- private boolean canEntryDecay() {
- return entry.notification.getNotification().fullScreenIntent == null;
- }
-
@Override
public int compareTo(HeadsUpEntry o) {
return postTime < o.postTime ? 1
@@ -487,7 +568,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
: -1;
}
- public void removeAutoCancelCallbacks() {
+ public void removeAutoRemovalCallbacks() {
mHandler.removeCallbacks(mRemoveHeadsUpRunnable);
}
@@ -495,11 +576,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 +606,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/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index f2b2f66..a7fdadc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -162,7 +162,7 @@ public class MobileDataControllerImpl implements NetworkController.MobileDataCon
usage.warningLevel = DEFAULT_WARNING_LEVEL;
}
if (usage != null) {
- usage.carrier = mNetworkController.getMobileNetworkName();
+ usage.carrier = mNetworkController.getMobileDataNetworkName();
}
return usage;
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index c3c6b12..22bf47c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -84,6 +84,7 @@ public class MobileSignalController extends SignalController<
mapIconSets();
mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault;
+ mLastState.networkNameData = mCurrentState.networkNameData = mNetworkNameDefault;
mLastState.enabled = mCurrentState.enabled = hasMobileData;
mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
// Get initial data sim state.
@@ -294,6 +295,7 @@ public class MobileSignalController extends SignalController<
if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+ intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN),
intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
notifyListenersIfNecessary();
@@ -322,14 +324,18 @@ public class MobileSignalController extends SignalController<
/**
* Updates the network's name based on incoming spn and plmn.
*/
- void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+ void updateNetworkName(boolean showSpn, String spn, String dataSpn,
+ boolean showPlmn, String plmn) {
if (CHATTY) {
- Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn
+ + " spn=" + spn + " dataSpn=" + dataSpn
+ " showPlmn=" + showPlmn + " plmn=" + plmn);
}
StringBuilder str = new StringBuilder();
+ StringBuilder strData = new StringBuilder();
if (showPlmn && plmn != null) {
str.append(plmn);
+ strData.append(plmn);
}
if (showSpn && spn != null) {
if (str.length() != 0) {
@@ -342,6 +348,17 @@ public class MobileSignalController extends SignalController<
} else {
mCurrentState.networkName = mNetworkNameDefault;
}
+ if (showSpn && dataSpn != null) {
+ if (strData.length() != 0) {
+ strData.append(mNetworkNameSeparator);
+ }
+ strData.append(dataSpn);
+ }
+ if (strData.length() != 0) {
+ mCurrentState.networkNameData = strData.toString();
+ } else {
+ mCurrentState.networkNameData = mNetworkNameDefault;
+ }
}
/**
@@ -492,6 +509,7 @@ public class MobileSignalController extends SignalController<
static class MobileState extends SignalController.State {
String networkName;
+ String networkNameData;
boolean dataSim;
boolean dataConnected;
boolean isEmergency;
@@ -505,6 +523,7 @@ public class MobileSignalController extends SignalController<
MobileState state = (MobileState) s;
dataSim = state.dataSim;
networkName = state.networkName;
+ networkNameData = state.networkNameData;
dataConnected = state.dataConnected;
inetForNetwork = state.inetForNetwork;
isEmergency = state.isEmergency;
@@ -518,6 +537,7 @@ public class MobileSignalController extends SignalController<
builder.append(',');
builder.append("dataSim=").append(dataSim).append(',');
builder.append("networkName=").append(networkName).append(',');
+ builder.append("networkNameData=").append(networkNameData).append(',');
builder.append("dataConnected=").append(dataConnected).append(',');
builder.append("inetForNetwork=").append(inetForNetwork).append(',');
builder.append("isEmergency=").append(isEmergency).append(',');
@@ -529,6 +549,7 @@ public class MobileSignalController extends SignalController<
public boolean equals(Object o) {
return super.equals(o)
&& Objects.equals(((MobileState) o).networkName, networkName)
+ && Objects.equals(((MobileState) o).networkNameData, networkNameData)
&& ((MobileState) o).dataSim == dataSim
&& ((MobileState) o).dataConnected == dataConnected
&& ((MobileState) o).isEmergency == isEmergency
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9adf028..92e0365 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -28,6 +28,7 @@ import android.net.NetworkCapabilities;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Looper;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -73,6 +74,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
// Subcontrollers.
@VisibleForTesting
final WifiSignalController mWifiSignalController;
+
+ @VisibleForTesting
+ final EthernetSignalController mEthernetSignalController;
+
@VisibleForTesting
final Map<Integer, MobileSignalController> mMobileSignalControllers =
new HashMap<Integer, MobileSignalController>();
@@ -111,12 +116,13 @@ public class NetworkControllerImpl extends BroadcastReceiver
/**
* Construct this controller object and register for updates.
*/
- public NetworkControllerImpl(Context context) {
+ public NetworkControllerImpl(Context context, Looper bgLooper) {
this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
(WifiManager) context.getSystemService(Context.WIFI_SERVICE),
SubscriptionManager.from(context), Config.readConfig(context),
- new AccessPointControllerImpl(context), new MobileDataControllerImpl(context));
+ new AccessPointControllerImpl(context, bgLooper),
+ new MobileDataControllerImpl(context));
registerListeners();
}
@@ -154,6 +160,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
mSignalsChangedCallbacks, mSignalClusters, this);
+ mEthernetSignalController = new EthernetSignalController(mContext, mSignalsChangedCallbacks,
+ mSignalClusters, this);
+
// AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
updateAirplaneMode(true /* force callback */);
}
@@ -239,9 +248,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
return mDefaultSignalController;
}
- public String getMobileNetworkName() {
+ public String getMobileDataNetworkName() {
MobileSignalController controller = getDataController();
- return controller != null ? controller.getState().networkName : "";
+ return controller != null ? controller.getState().networkNameData : "";
}
public boolean isEmergencyOnly() {
@@ -281,6 +290,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
R.string.accessibility_airplane_mode);
cluster.setNoSims(mHasNoSims);
mWifiSignalController.notifyListeners();
+ mEthernetSignalController.notifyListeners();
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
mobileSignalController.notifyListeners();
}
@@ -291,6 +301,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
cb.onAirplaneModeChanged(mAirplaneMode);
cb.onNoSimVisibleChanged(mHasNoSims);
mWifiSignalController.notifyListeners();
+ mEthernetSignalController.notifyListeners();
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
mobileSignalController.notifyListeners();
}
@@ -501,6 +512,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mobileSignalController.notifyListeners();
}
mWifiSignalController.notifyListeners();
+ mEthernetSignalController.notifyListeners();
}
/**
@@ -560,6 +572,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
mWifiSignalController.setInetCondition(
mValidatedTransports.get(mWifiSignalController.getTransportType()) ? 1 : 0);
+
+ mEthernetSignalController.setConnected(
+ mConnectedTransports.get(mEthernetSignalController.getTransportType()));
+ mEthernetSignalController.setInetCondition(
+ mValidatedTransports.get(mEthernetSignalController.getTransportType()) ? 1 : 0);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -586,6 +603,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
mWifiSignalController.dump(pw);
+ mEthernetSignalController.dump(pw);
+
mAccessPoints.dump(pw);
}
@@ -731,6 +750,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
void setSubs(List<SubscriptionInfo> subs);
void setNoSims(boolean show);
+ void setEthernetIndicators(boolean visible, int icon, String contentDescription);
+
void setIsAirplaneMode(boolean is, int airplaneIcon, int contentDescription);
}
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..4269c19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -21,11 +21,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.util.Log;
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;
@@ -49,6 +51,15 @@ public class PreviewInflater {
public View inflatePreview(Intent intent) {
WidgetInfo info = getWidgetInfo(intent);
+ return inflatePreview(info);
+ }
+
+ public View inflatePreviewFromService(ComponentName componentName) {
+ WidgetInfo info = getWidgetInfoFromService(componentName);
+ return inflatePreview(info);
+ }
+
+ private KeyguardPreviewContainer inflatePreview(WidgetInfo info) {
if (info == null) {
return null;
}
@@ -76,33 +87,53 @@ public class PreviewInflater {
return widgetView;
}
- private WidgetInfo getWidgetInfo(Intent intent) {
+ private WidgetInfo getWidgetInfoFromService(ComponentName componentName) {
+ PackageManager packageManager = mContext.getPackageManager();
+ // Look for the preview specified in the service meta-data
+ try {
+ Bundle metaData = packageManager.getServiceInfo(
+ componentName, PackageManager.GET_META_DATA).metaData;
+ return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString()
+ + " not found", e);
+ }
+ return null;
+ }
+
+ private WidgetInfo getWidgetInfoFromMetaData(String contextPackage,
+ Bundle metaData) {
+ if (metaData == null) {
+ return null;
+ }
+ int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
+ if (layoutId == 0) {
+ return null;
+ }
WidgetInfo info = new WidgetInfo();
+ info.contextPackage = contextPackage;
+ info.layoutId = layoutId;
+ return info;
+ }
+
+ private WidgetInfo getWidgetInfo(Intent intent) {
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;
}
if (resolved == null || resolved.activityInfo == null) {
return null;
}
- if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) {
- return null;
- }
- int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT);
- if (layoutId == 0) {
- return null;
- }
- info.contextPackage = resolved.activityInfo.packageName;
- info.layoutId = layoutId;
- return info;
+ return getWidgetInfoFromMetaData(resolved.activityInfo.packageName,
+ resolved.activityInfo.metaData);
}
public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
index c204814..f3322a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
@@ -153,7 +153,11 @@ public abstract class SignalController<T extends SignalController.State,
return getIcons().mSbDarkIcons[mCurrentState.inetCondition][mCurrentState.level];
}
} else if (mCurrentState.enabled) {
- return getIcons().mSbDiscState;
+ if (light) {
+ return getIcons().mSbDiscState;
+ } else {
+ return getIcons().mSbDarkDiscState;
+ }
} else {
return getIcons().mSbNullState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 194bcfa..ad27c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -43,6 +43,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.UserIcons;
import com.android.systemui.BitmapHelper;
import com.android.systemui.GuestResumeSessionReceiver;
@@ -548,6 +549,11 @@ public class UserSwitcherController {
@Override
public void setToggleState(boolean state) {
}
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_USERDETAIL;
+ }
};
private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
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..bd3b9eb 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
@@ -486,10 +485,10 @@ public class NotificationStackScrollLayout extends ViewGroup
int minStackHeight = getMinStackHeight();
int stackHeight;
float paddingOffset;
- boolean trackingHeadsUp = mTrackingHeadsUp;
- int normalExpandPositionStart = trackingHeadsUp ? mHeadsUpManager.getTopHeadsUpHeight()
+ boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
+ 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);
@@ -609,7 +608,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
- if (isPinnedHeadsUp(animView) && canChildBeDismissed(animView)) {
+ if (!mIsExpanded && isPinnedHeadsUp(animView) && canChildBeDismissed(animView)) {
mScrimController.setTopHeadsUpDragAmount(animView,
Math.min(Math.abs(swipeProgress - 1.0f), 1.0f));
}
@@ -619,17 +618,17 @@ public class NotificationStackScrollLayout extends ViewGroup
public void onBeginDrag(View v) {
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
- if (mAnimationsEnabled && !isPinnedHeadsUp(v)) {
+ if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
mDragAnimPendingChildren.add(v);
mNeedsAnimation = true;
}
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 (!mIsExpanded && 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;
@@ -1870,17 +1871,18 @@ public class NotificationStackScrollLayout extends ViewGroup
boolean isHeadsUp = eventPair.second;
int type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_OTHER;
boolean onBottom = false;
+ boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
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 (isHeadsUp && (mAddedHeadsUpChildren.contains(row) || pinnedAndClosed)) {
+ if (pinnedAndClosed || 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 = !pinnedAndClosed;
}
AnimationEvent event = new AnimationEvent(row, type);
event.headsUpFromBottom = onBottom;
@@ -2670,7 +2672,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..081a9c5 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,7 @@ public class StackScrollAlgorithm {
StackViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
- if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) {
+ if (ambientState.isShadeExpanded()) {
viewState.alpha = 1;
}
}
@@ -324,14 +324,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 +372,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,26 +507,28 @@ public class StackScrollAlgorithm {
}
StackViewState childState = resultState.getViewStateForView(row);
boolean isTopEntry = topHeadsUpEntry == row;
- if (!row.isInShade()) {
- childState.yTranslation = 0;
- childState.height = row.getHeadsUpHeight();
- if (!isTopEntry) {
- // Ensure that a headsUp is never below the topmost headsUp
- StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
- childState.height = row.getHeadsUpHeight();
- childState.yTranslation = topState.yTranslation + topState.height
- - childState.height;
- }
- } else if (mIsExpanded) {
+ if (mIsExpanded) {
if (isTopEntry) {
childState.height += row.getHeadsUpHeight() - mCollapsedSize;
}
childState.height = Math.max(childState.height, row.getHeadsUpHeight());
- // Ensure that the heads up is always visible even when scrolled of from the bottom
+ // Ensure that the heads up is always visible even when scrolled off from the bottom
float bottomPosition = ambientState.getMaxHeadsUpTranslation() - childState.height;
childState.yTranslation = Math.min(childState.yTranslation,
bottomPosition);
}
+ if (row.isPinned()) {
+ childState.yTranslation = Math.max(childState.yTranslation, 0);
+ childState.height = row.getHeadsUpHeight();
+ if (!isTopEntry) {
+ // 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
+ - childState.height;
+ }
+ }
}
}
@@ -588,7 +582,7 @@ public class StackScrollAlgorithm {
return row.getIntrinsicHeight();
} else if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
- return expandableView.getActualHeight();
+ return expandableView.getIntrinsicHeight();
}
return child == null? mCollapsedSize : child.getHeight();
}
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..eac5e79 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() {
@@ -183,7 +163,7 @@ public class StackStateAnimator {
// This is a heads up animation
return false;
}
- if (mHostLayout.isPinnedHeadsUp(child)) {
+ if (NotificationStackScrollLayout.isPinnedHeadsUp(child)) {
// This is another headsUp which might move. Let's animate!
return false;
}
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/tuner/AutoScrollView.java b/packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java
new file mode 100644
index 0000000..6aea2cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/AutoScrollView.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tuner;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.widget.ScrollView;
+
+public class AutoScrollView extends ScrollView {
+
+ private static final float SCROLL_PERCENT = .10f;
+
+ public AutoScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean onDragEvent(DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_LOCATION:
+ int y = (int) event.getY();
+ int height = getHeight();
+ int scrollPadding = (int) (height * SCROLL_PERCENT);
+ if (y < scrollPadding) {
+ scrollBy(0, y - scrollPadding);
+ } else if (y > height - scrollPadding) {
+ scrollBy(0, y - height + scrollPadding);
+ }
+ break;
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
new file mode 100644
index 0000000..5cf0813
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -0,0 +1,451 @@
+/*
+ * 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.tuner;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.ClipData;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings.Secure;
+import android.util.Log;
+import android.view.DragEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnDragListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ScrollView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.QSTile.ResourceIcon;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.tiles.IntentTile;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.List;
+
+public class QsTuner extends Fragment implements Callback {
+
+ private static final String TAG = "QsTuner";
+
+ private static final int MENU_RESET = Menu.FIRST;
+
+ private DraggableQsPanel mQsPanel;
+ private CustomHost mTileHost;
+
+ private FrameLayout mDropTarget;
+
+ private ScrollView mScrollRoot;
+
+ private FrameLayout mAddTarget;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(0, MENU_RESET, 0, com.android.internal.R.string.reset);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_RESET:
+ mTileHost.reset();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mScrollRoot = (ScrollView) inflater.inflate(R.layout.tuner_qs, container, false);
+
+ mQsPanel = new DraggableQsPanel(getContext());
+ mTileHost = new CustomHost(getContext());
+ mTileHost.setCallback(this);
+ mQsPanel.setTiles(mTileHost.getTiles());
+ mQsPanel.setHost(mTileHost);
+ mQsPanel.refreshAllTiles();
+ ((ViewGroup) mScrollRoot.findViewById(R.id.all_details)).addView(mQsPanel, 0);
+
+ mDropTarget = (FrameLayout) mScrollRoot.findViewById(R.id.remove_target);
+ setupDropTarget();
+ mAddTarget = (FrameLayout) mScrollRoot.findViewById(R.id.add_target);
+ setupAddTarget();
+ return mScrollRoot;
+ }
+
+ private void setupDropTarget() {
+ QSTileView tileView = new QSTileView(getContext());
+ QSTile.State state = new QSTile.State();
+ state.visible = true;
+ state.icon = ResourceIcon.get(R.drawable.ic_delete);
+ state.label = getString(com.android.internal.R.string.delete);
+ tileView.onStateChanged(state);
+ mDropTarget.addView(tileView);
+ mDropTarget.setVisibility(View.GONE);
+ new DragHelper(tileView, new DropListener() {
+ @Override
+ public void onDrop(String sourceText) {
+ mTileHost.remove(sourceText);
+ }
+ });
+ }
+
+ private void setupAddTarget() {
+ QSTileView tileView = new QSTileView(getContext());
+ QSTile.State state = new QSTile.State();
+ state.visible = true;
+ state.icon = ResourceIcon.get(R.drawable.ic_add_circle_qs);
+ state.label = getString(R.string.add_tile);
+ tileView.onStateChanged(state);
+ mAddTarget.addView(tileView);
+ tileView.setClickable(true);
+ tileView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mTileHost.showAddDialog();
+ }
+ });
+ }
+
+ public void onStartDrag() {
+ mDropTarget.setVisibility(View.VISIBLE);
+ mAddTarget.setVisibility(View.GONE);
+ }
+
+ public void stopDrag() {
+ mDropTarget.setVisibility(View.GONE);
+ mAddTarget.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onTilesChanged() {
+ mQsPanel.setTiles(mTileHost.getTiles());
+ }
+
+ private static int getLabelResource(String spec) {
+ if (spec.equals("wifi")) return R.string.quick_settings_wifi_label;
+ else if (spec.equals("bt")) return R.string.quick_settings_bluetooth_label;
+ else if (spec.equals("inversion")) return R.string.quick_settings_inversion_label;
+ else if (spec.equals("cell")) return R.string.quick_settings_cellular_detail_title;
+ else if (spec.equals("airplane")) return R.string.quick_settings_airplane_mode_label;
+ else if (spec.equals("dnd")) return R.string.quick_settings_dnd_label;
+ else if (spec.equals("rotation")) return R.string.quick_settings_rotation_locked_label;
+ else if (spec.equals("flashlight")) return R.string.quick_settings_flashlight_label;
+ else if (spec.equals("location")) return R.string.quick_settings_location_label;
+ else if (spec.equals("cast")) return R.string.quick_settings_cast_title;
+ else if (spec.equals("hotspot")) return R.string.quick_settings_hotspot_label;
+ return 0;
+ }
+
+ private static class CustomHost extends QSTileHost {
+
+ public CustomHost(Context context) {
+ super(context, null, null, null, null, null, null, null, null, null,
+ null, null, null);
+ }
+
+ @Override
+ protected QSTile<?> createTile(String tileSpec) {
+ return new DraggableTile(this, tileSpec);
+ }
+
+ public void replace(String oldTile, String newTile) {
+ if (oldTile.equals(newTile)) {
+ return;
+ }
+ List<String> order = loadTileSpecs();
+ int index = order.indexOf(oldTile);
+ if (index < 0) {
+ Log.e(TAG, "Can't find " + oldTile);
+ return;
+ }
+ order.remove(newTile);
+ order.add(index, newTile);
+ setTiles(order);
+ }
+
+ public void remove(String tile) {
+ List<String> tiles = loadTileSpecs();
+ tiles.remove(tile);
+ setTiles(tiles);
+ }
+
+ public void add(String tile) {
+ List<String> tiles = loadTileSpecs();
+ tiles.add(tile);
+ setTiles(tiles);
+ }
+
+ public void reset() {
+ Secure.putStringForUser(getContext().getContentResolver(),
+ TILES_SETTING, "default", mUserTracker.getCurrentUserId());
+ }
+
+ private void setTiles(List<String> tiles) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < tiles.size(); i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(tiles.get(i));
+ }
+ Secure.putStringForUser(getContext().getContentResolver(),
+ TILES_SETTING, builder.toString(), mUserTracker.getCurrentUserId());
+ }
+
+ public void showAddDialog() {
+ List<String> tiles = loadTileSpecs();
+ String[] defaults =
+ getContext().getString(R.string.quick_settings_tiles_default).split(",");
+ final String[] available = new String[defaults.length + 1 - tiles.size()];
+ int index = 0;
+ for (int i = 0; i < defaults.length; i++) {
+ if (tiles.contains(defaults[i])) {
+ continue;
+ }
+ int resource = getLabelResource(defaults[i]);
+ if (resource != 0) {
+ available[index++] = getContext().getString(resource);
+ } else {
+ available[index++] = defaults[i];
+ }
+ }
+ available[index++] = getContext().getString(R.string.broadcast_tile);
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.add_tile)
+ .setItems(available, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which < available.length - 1) {
+ add(available[which]);
+ } else {
+ showBroadcastTileDialog();
+ }
+ }
+ }).show();
+ }
+
+ public void showBroadcastTileDialog() {
+ final EditText editText = new EditText(getContext());
+ new AlertDialog.Builder(getContext())
+ .setTitle(R.string.broadcast_tile)
+ .setView(editText)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String action = editText.getText().toString();
+ if (isValid(action)) {
+ add(IntentTile.PREFIX + action + ')');
+ }
+ }
+ }).show();
+ }
+
+ private boolean isValid(String action) {
+ for (int i = 0; i < action.length(); i++) {
+ char c = action.charAt(i);
+ if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '.') {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static class DraggableTile extends QSTile<QSTile.State>
+ implements DropListener {
+ private String mSpec;
+ private QSTileView mView;
+
+ protected DraggableTile(QSTile.Host host, String tileSpec) {
+ super(host);
+ Log.d(TAG, "Creating tile " + tileSpec);
+ mSpec = tileSpec;
+ }
+
+ @Override
+ public QSTileView createTileView(Context context) {
+ mView = super.createTileView(context);
+ return mView;
+ }
+
+ @Override
+ public boolean supportsDualTargets() {
+ return "wifi".equals(mSpec) || "bt".equals(mSpec);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ }
+
+ @Override
+ protected QSTile.State newTileState() {
+ return new QSTile.State();
+ }
+
+ @Override
+ protected void handleClick() {
+ }
+
+ @Override
+ protected void handleUpdateState(QSTile.State state, Object arg) {
+ state.visible = true;
+ state.icon = ResourceIcon.get(getIcon());
+ state.label = getLabel();
+ }
+
+ private String getLabel() {
+ int resource = getLabelResource(mSpec);
+ if (resource != 0) {
+ return mContext.getString(resource);
+ }
+ if (mSpec.startsWith(IntentTile.PREFIX)) {
+ int lastDot = mSpec.lastIndexOf('.');
+ if (lastDot >= 0) {
+ return mSpec.substring(lastDot + 1, mSpec.length() - 1);
+ } else {
+ return mSpec.substring(IntentTile.PREFIX.length(), mSpec.length() - 1);
+ }
+ }
+ return mSpec;
+ }
+
+ private int getIcon() {
+ if (mSpec.equals("wifi")) return R.drawable.ic_qs_wifi_full_3;
+ else if (mSpec.equals("bt")) return R.drawable.ic_qs_bluetooth_connected;
+ else if (mSpec.equals("inversion")) return R.drawable.ic_invert_colors_enable;
+ else if (mSpec.equals("cell")) return R.drawable.ic_qs_signal_full_3;
+ else if (mSpec.equals("airplane")) return R.drawable.ic_signal_airplane_enable;
+ else if (mSpec.equals("dnd")) return R.drawable.ic_qs_dnd_on;
+ else if (mSpec.equals("rotation")) return R.drawable.ic_portrait_from_auto_rotate;
+ else if (mSpec.equals("flashlight")) return R.drawable.ic_signal_flashlight_enable;
+ else if (mSpec.equals("location")) return R.drawable.ic_signal_location_enable;
+ else if (mSpec.equals("cast")) return R.drawable.ic_qs_cast_on;
+ else if (mSpec.equals("hotspot")) return R.drawable.ic_hotspot_enable;
+ return R.drawable.android;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return 20000;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof DraggableTile) {
+ return mSpec.equals(((DraggableTile) o).mSpec);
+ }
+ return false;
+ }
+
+ @Override
+ public void onDrop(String sourceText) {
+ ((CustomHost) mHost).replace(mSpec, sourceText);
+ }
+
+ }
+
+ private class DragHelper implements OnDragListener {
+
+ private final View mView;
+ private final DropListener mListener;
+
+ public DragHelper(View view, DropListener dropListener) {
+ mView = view;
+ mListener = dropListener;
+ mView.setOnDragListener(this);
+ }
+
+ @Override
+ public boolean onDrag(View v, DragEvent event) {
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DRAG_ENTERED:
+ mView.setBackgroundColor(0x77ffffff);
+ break;
+ case DragEvent.ACTION_DRAG_ENDED:
+ stopDrag();
+ case DragEvent.ACTION_DRAG_EXITED:
+ mView.setBackgroundColor(0x0);
+ break;
+ case DragEvent.ACTION_DROP:
+ stopDrag();
+ String text = event.getClipData().getItemAt(0).getText().toString();
+ mListener.onDrop(text);
+ break;
+ }
+ return true;
+ }
+
+ }
+
+ public interface DropListener {
+ void onDrop(String sourceText);
+ }
+
+ private class DraggableQsPanel extends QSPanel implements OnTouchListener {
+ public DraggableQsPanel(Context context) {
+ super(context);
+ mBrightnessView.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ for (TileRecord r : mRecords) {
+ new DragHelper(r.tileView, (DraggableTile) r.tile);
+ r.tileView.setTag(r.tile);
+ r.tileView.setOnTouchListener(this);
+
+ for (int i = 0; i < r.tileView.getChildCount(); i++) {
+ r.tileView.getChildAt(i).setClickable(false);
+ }
+ }
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ String tileSpec = (String) ((DraggableTile) v.getTag()).mSpec;
+ ClipData data = ClipData.newPlainText(tileSpec, tileSpec);
+ v.startDrag(data, new View.DragShadowBuilder(v), null, 0);
+ onStartDrag();
+ return true;
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
new file mode 100644
index 0000000..c84f618
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.tuner;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class TunerActivity extends Activity {
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getFragmentManager().beginTransaction().replace(android.R.id.content, new TunerFragment())
+ .commit();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
new file mode 100644
index 0000000..457bade
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -0,0 +1,60 @@
+/*
+ * 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.tuner;
+
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceFragment;
+import android.view.MenuItem;
+
+import com.android.systemui.R;
+
+public class TunerFragment extends PreferenceFragment {
+
+ private static final String KEY_QS_TUNER = "qs_tuner";
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.tuner_prefs);
+ getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
+ setHasOptionsMenu(true);
+
+ findPreference(KEY_QS_TUNER).setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, new QsTuner(), "QsTuner");
+ ft.addToBackStack(null);
+ ft.commit();
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ getActivity().finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 240c210..23813d1 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.ic_sd_card_48dp)
+ .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,25 @@ 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)))
- .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
+ .addAction(new Action(R.drawable.ic_settings_24dp,
+ mContext.getString(R.string.ext_media_init_action), initIntent))
+ .addAction(new Action(R.drawable.ic_eject_24dp,
+ mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
+ .setContentIntent(initIntent)
.setDeleteIntent(buildSnoozeIntent(vol))
.setCategory(Notification.CATEGORY_SYSTEM)
.build();
@@ -182,11 +328,15 @@ 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)))
- .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
+ .addAction(new Action(R.drawable.ic_folder_24dp,
+ mContext.getString(R.string.ext_media_browse_action),
+ browseIntent))
+ .addAction(new Action(R.drawable.ic_eject_24dp,
+ 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 +371,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,26 +410,112 @@ 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.ic_sd_card_48dp)
+ .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.ic_sd_card_48dp)
+ .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;
+ return R.drawable.ic_sd_card_48dp;
default:
- return R.drawable.stat_notify_sdcard;
+ return R.drawable.ic_sd_card_48dp;
}
- } else if (vol.disk.isUsb()) {
- return R.drawable.stat_sys_data_usb;
+ } else if (disk.isUsb()) {
+ return R.drawable.ic_usb_48dp;
} else {
- return R.drawable.stat_notify_sdcard;
+ return R.drawable.ic_sd_card_48dp;
}
}
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 +524,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 +565,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 +588,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/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index 23a65e8..ca32567 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -93,7 +93,7 @@ public class UsbResolverActivity extends ResolverActivity {
}
@Override
- protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
+ protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
final ResolveInfo ri = target.getResolveInfo();
try {
IBinder b = ServiceManager.getService(USB_SERVICE);
@@ -129,5 +129,6 @@ public class UsbResolverActivity extends ResolverActivity {
} catch (RemoteException e) {
Log.e(TAG, "onIntentSelected failed", e);
}
+ return true;
}
}
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..6e0ca3c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -16,6 +16,9 @@
package com.android.systemui.volume;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -23,6 +26,7 @@ import android.annotation.SuppressLint;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -32,18 +36,20 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.AudioSystem;
+import android.os.Debug;
import android.os.Handler;
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;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
import android.view.View.OnLayoutChangeListener;
import android.view.View.OnTouchListener;
@@ -51,8 +57,10 @@ import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
import android.view.animation.DecelerateInterpolator;
-import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -90,26 +98,23 @@ 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();
+ private final Accessibility mAccessibility = new Accessibility();
+ private final ColorStateList mActiveSliderTint;
+ private final ColorStateList mInactiveSliderTint;
private boolean mShowing;
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 +123,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 +146,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;
@@ -150,6 +155,8 @@ public class VolumeDialog {
lp.gravity = Gravity.TOP;
window.setAttributes(lp);
+ mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
+ mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
mDialog.setContentView(R.layout.volume_dialog);
mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
@@ -176,22 +183,22 @@ 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);
+
+ mAccessibility.init();
controller.addCallback(mControllerCallbackH, mHandler);
controller.getState();
}
+ private ColorStateList loadColorStateList(int colorResId) {
+ return ColorStateList.valueOf(mContext.getColor(colorResId));
+ }
+
private void updateWindowWidthH() {
final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams();
final DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
@@ -217,18 +224,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 +310,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);
}
@@ -436,15 +430,17 @@ public class VolumeDialog {
protected void rescheduleTimeoutH() {
mHandler.removeMessages(H.DISMISS);
- final int timeout = computeTimeoutH();
- if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout);
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
+ int timeout = -1;
+ if (!mAccessibility.mFeedbackEnabled) {
+ timeout = computeTimeoutH();
+ mHandler.sendMessageDelayed(mHandler
+ .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
+ }
+ if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
mController.userActivity();
}
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;
@@ -503,6 +499,8 @@ public class VolumeDialog {
if (res == mExpandButtonRes) return;
mExpandButtonRes = res;
mExpandButton.setImageResource(res);
+ mExpandButton.setContentDescription(mContext.getString(mExpanded ?
+ R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand));
}
private boolean isVisibleH(VolumeRow row, boolean isActive) {
@@ -515,18 +513,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,9 +531,9 @@ 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);
+ updateVolumeRowSliderTintH(row, isActive);
}
}
@@ -585,51 +574,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 +589,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 +618,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 +634,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)
@@ -703,12 +659,24 @@ public class VolumeDialog {
: (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes)
? Events.ICON_STATE_UNMUTE
: Events.ICON_STATE_UNKNOWN;
+ row.icon.setContentDescription(ss.name);
// update slider
- updateVolumeRowSliderH(row);
+ updateVolumeRowSliderH(row, zenMuted);
+ }
+
+ private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
+ final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
+ : mInactiveSliderTint;
+ if (tint == row.cachedSliderTint) return;
+ row.cachedSliderTint = tint;
+ row.slider.setProgressTintList(tint);
+ row.slider.setThumbTintList(tint);
}
- private void updateVolumeRowSliderH(VolumeRow row) {
+ private void updateVolumeRowSliderH(VolumeRow row, boolean zenMuted) {
+ row.slider.setEnabled(!zenMuted);
+ updateVolumeRowSliderTintH(row, row.stream == mActiveStream);
if (row.tracking) {
return; // don't update if user is sliding
}
@@ -840,6 +808,7 @@ public class VolumeDialog {
public void onConfigurationChanged() {
updateWindowWidthH();
mSpTexts.update();
+ mZenFooter.onConfigurationChanged();
}
@Override
@@ -887,46 +856,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;
@@ -1041,6 +970,56 @@ public class VolumeDialog {
}
}
+ private final class Accessibility {
+ private AccessibilityManager mMgr;
+ private boolean mFeedbackEnabled;
+
+ public void init() {
+ mMgr = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mDialogView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // noop
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ updateFeedbackEnabled();
+ }
+ });
+ mDialogView.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+ AccessibilityEvent event) {
+ rescheduleTimeoutH();
+ return super.onRequestSendAccessibilityEvent(host, child, event);
+ }
+ });
+ mMgr.addAccessibilityStateChangeListener(new AccessibilityStateChangeListener() {
+ @Override
+ public void onAccessibilityStateChanged(boolean enabled) {
+ updateFeedbackEnabled();
+ }
+ });
+ updateFeedbackEnabled();
+ }
+
+ private void updateFeedbackEnabled() {
+ mFeedbackEnabled = computeFeedbackEnabled();
+ }
+
+ private boolean computeFeedbackEnabled() {
+ final List<AccessibilityServiceInfo> services =
+ mMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
+ for (AccessibilityServiceInfo asi : services) {
+ if ((asi.feedbackType & FEEDBACK_ALL_MASK) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
private static class VolumeRow {
private View view;
private View space;
@@ -1057,6 +1036,7 @@ public class VolumeDialog {
private int iconMuteRes;
private boolean important;
private int cachedIconRes;
+ private ColorStateList cachedSliderTint;
private int iconState; // from Events
private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
private int cachedExpandButtonRes;
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..6d67d11 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -16,20 +16,13 @@
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.ImageView;
import android.widget.LinearLayout;
-import android.widget.Switch;
import android.widget.TextView;
import com.android.systemui.R;
@@ -38,70 +31,43 @@ 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 final SpTexts mSpTexts;
- 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 ImageView mIcon;
private TextView mSummaryLine1;
private TextView mSummaryLine2;
- private boolean mFooterExpanded;
+ private TextView 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();
+ mSpTexts = new SpTexts(mContext);
+ 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);
+ mIcon = (ImageView) findViewById(R.id.volume_zen_icon);
+ mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_summary_line_1);
+ mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_summary_line_2);
+ mEndNowButton = (TextView) findViewById(R.id.volume_zen_end_now);
+ mSpTexts.add(mSummaryLine1);
+ mSpTexts.add(mSummaryLine2);
+ mSpTexts.add(mEndNowButton);
}
- 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 +77,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 +117,22 @@ 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);
+ mIcon.setImageResource(isZenNone() ? R.drawable.ic_dnd_total_silence : R.drawable.ic_dnd);
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(), true /*shortVersion*/);
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();
+ public void onConfigurationChanged() {
+ mSpTexts.update();
}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 1b563dc..8dfa9b0 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;
@@ -50,6 +48,7 @@ import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -85,22 +84,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 +104,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 +113,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 +120,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 +134,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 +152,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 +176,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 +206,6 @@ public class ZenModePanel extends LinearLayout {
mSessionZen = mAttachedZen;
mTransitionHelper.clear();
setSessionExitCondition(copy(mExitCondition));
- refreshExitConditionText();
updateWidgets();
setRequestingConditions(!mHidden);
}
@@ -274,9 +219,6 @@ public class ZenModePanel extends LinearLayout {
mAttachedZen = -1;
mSessionZen = -1;
setSessionExitCondition(null);
- if (!mEmbedded) {
- setExpanded(false);
- }
setRequestingConditions(false);
mTransitionHelper.clear();
}
@@ -359,7 +301,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 +316,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 +335,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 +366,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 +416,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) {
@@ -514,7 +438,8 @@ public class ZenModePanel extends LinearLayout {
final long span = time - now;
if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
return ZenModeConfig.toTimeCondition(context,
- time, Math.round(span / (float) MINUTES_MS), now, ActivityManager.getCurrentUser());
+ time, Math.round(span / (float) MINUTES_MS), now, ActivityManager.getCurrentUser(),
+ false /*shortVersion*/);
}
private void handleUpdateConditions(Condition[] conditions) {
@@ -675,6 +600,7 @@ public class ZenModePanel extends LinearLayout {
if (childTag == null || childTag == tag) continue;
childTag.rb.setChecked(false);
}
+ MetricsLogger.action(mContext, MetricsLogger.QS_DND_CONDITION_SELECT);
select(tag.condition);
announceConditionSelection(tag);
}
@@ -761,13 +687,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;
@@ -777,6 +703,7 @@ public class ZenModePanel extends LinearLayout {
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up) {
+ MetricsLogger.action(mContext, MetricsLogger.QS_DND_TIME, up);
Condition newCondition = null;
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
@@ -791,7 +718,8 @@ public class ZenModePanel extends LinearLayout {
if (up && bucketTime > time || !up && bucketTime < time) {
mBucketIndex = j;
newCondition = ZenModeConfig.toTimeCondition(mContext,
- bucketTime, bucketMinutes, now, ActivityManager.getCurrentUser());
+ bucketTime, bucketMinutes, now, ActivityManager.getCurrentUser(),
+ false /*shortVersion*/);
break;
}
}
@@ -837,12 +765,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 +809,6 @@ public class ZenModePanel extends LinearLayout {
}
public interface Callback {
- void onMoreSettings();
void onPrioritySettings();
void onInteraction();
void onExpanded(boolean expanded);
@@ -907,7 +828,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 +837,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 +864,8 @@ public class ZenModePanel extends LinearLayout {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
updateMinuteIndex();
updateNoneSelected();
- updateConfirmedIntroduction();
+ updateConfirmedPriorityIntroduction();
+ updateConfirmedSilenceIntroduction();
}
private void updateMinuteIndex() {
@@ -968,12 +888,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 +911,17 @@ 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;
+ MetricsLogger.action(mContext, MetricsLogger.QS_DND_ZEN_SELECT, zen);
+ 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);
+ }
}
});
}