summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
authorJiyong Park <jiyong@google.com>2018-04-11 21:14:26 +0900
committerJiyong Park <jiyong@google.com>2018-04-11 21:14:26 +0900
commit1452baeffa18c2760dac56bee26c20fa12a499a3 (patch)
treee1e6c5922257450926c99e481c50fd42cedba61e /packages/SystemUI/src
parent5c521b2e9db825519d7b287acc58378912b56b69 (diff)
parent8dcd862081e335405aecacd1d10e095cd78f7116 (diff)
Update to PPR1.180411.001
Conflicts: services/core/java/com/android/server/ConnectivityService.java services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java services/core/java/com/android/server/om/OverlayManagerSettings.java Change-Id: I44e49cb1dc1cf3f10e12b49ca84d0cb486925d08
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/OverviewProxyService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java72
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java144
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java360
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java364
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java15
70 files changed, 1432 insertions, 837 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index d63ad0840734..00cd5a7b1689 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -265,11 +265,11 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
mPendingLockCheck.cancel(false);
mPendingLockCheck = null;
}
+ reset();
}
@Override
public void onResume(int reason) {
- reset();
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index c1cff9e8f735..adb246013d5d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -107,6 +107,13 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
new View[]{
null, mEcaView, null
}};
+
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ });
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 75c52d8ead65..7cc37c476e31 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -205,6 +205,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
}
});
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ });
+ }
+
// If there's more than one IME, enable the IME switcher button
updateSwitchImeButton();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 651831eea517..174dcaba0759 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -157,6 +157,13 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
if (button != null) {
button.setCallback(this);
}
+
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ });
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index f0a823e8af34..90e092d57ebd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -78,6 +78,11 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
}
break;
}
+ case READY: {
+ mRemainingAttempts = -1;
+ resetState();
+ break;
+ }
default:
resetState();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index ce16efbb311f..ff3af17bb61d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -216,8 +216,7 @@ public class KeyguardStatusView extends GridLayout {
}
public void refreshTime() {
- mClockView.setFormat12Hour(Patterns.clockView12);
- mClockView.setFormat24Hour(Patterns.clockView24);
+ mClockView.refresh();
}
private void refresh() {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 1ae06d751255..0683514f6f2a 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -81,6 +81,14 @@ public class BatteryMeterView extends LinearLayout implements
private float mDarkIntensity;
private int mUser;
+ /**
+ * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings.
+ */
+ private boolean mUseWallpaperTextColors;
+
+ private int mNonAdaptedForegroundColor;
+ private int mNonAdaptedBackgroundColor;
+
public BatteryMeterView(Context context) {
this(context, null, 0);
}
@@ -140,6 +148,29 @@ public class BatteryMeterView extends LinearLayout implements
updateShowPercent();
}
+ /**
+ * Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
+ * revert back to dark-mode-based/tinted colors.
+ *
+ * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for all
+ * components
+ */
+ public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
+ if (shouldUseWallpaperTextColor == mUseWallpaperTextColors) {
+ return;
+ }
+
+ mUseWallpaperTextColors = shouldUseWallpaperTextColor;
+
+ if (mUseWallpaperTextColors) {
+ updateColors(
+ Utils.getColorAttr(mContext, R.attr.wallpaperTextColor),
+ Utils.getColorAttr(mContext, R.attr.wallpaperTextColorSecondary));
+ } else {
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ }
+ }
+
public void setColorsFromContext(Context context) {
if (context == null) {
return;
@@ -179,7 +210,8 @@ public class BatteryMeterView extends LinearLayout implements
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
updateShowPercent();
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class)
+ .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Dependency.get(ConfigurationController.class).addCallback(this);
mUserTracker.startTracking();
}
@@ -273,19 +305,23 @@ public class BatteryMeterView extends LinearLayout implements
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
mDarkIntensity = darkIntensity;
+
float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
- int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
- mDarkModeFillColor);
- int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
- mDarkModeBackgroundColor);
- mDrawable.setColors(foreground, background);
- setTextColor(foreground);
+ mNonAdaptedForegroundColor = getColorForDarkIntensity(
+ intensity, mLightModeFillColor, mDarkModeFillColor);
+ mNonAdaptedBackgroundColor = getColorForDarkIntensity(
+ intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
+
+ if (!mUseWallpaperTextColors) {
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ }
}
- public void setTextColor(int color) {
- mTextColor = color;
+ private void updateColors(int foregroundColor, int backgroundColor) {
+ mDrawable.setColors(foregroundColor, backgroundColor);
+ mTextColor = foregroundColor;
if (mBatteryPercentView != null) {
- mBatteryPercentView.setTextColor(color);
+ mBatteryPercentView.setTextColor(foregroundColor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a4f8d8c1bcd2..b8a57bfe885a 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -444,13 +444,7 @@ public class ImageWallpaper extends WallpaperService {
final Surface surface = getSurfaceHolder().getSurface();
surface.hwuiDestroy();
- mLoader = new AsyncTask<Void, Void, Bitmap>() {
- @Override
- protected Bitmap doInBackground(Void... params) {
- mWallpaperManager.forgetLoadedWallpaper();
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ mWallpaperManager.forgetLoadedWallpaper();
}
private void scheduleUnloadWallpaper() {
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 8e5984244476..b1020cfb5a84 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -52,6 +52,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
@@ -315,7 +316,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
private void updateEnabledState() {
- mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, 0,
+ mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
+ MATCH_DIRECT_BOOT_UNAWARE,
ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 039e7b5a6613..c01cafaaa9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -25,6 +25,7 @@ import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.Dependency.DependencyProvider;
import com.android.systemui.classifier.FalsingManager;
@@ -44,6 +45,7 @@ import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
@@ -100,12 +102,13 @@ public class SystemUIFactory {
dismissCallbackRegistry, FalsingManager.getInstance(context));
}
- public ScrimController createScrimController(LightBarController lightBarController,
- ScrimView scrimBehind, ScrimView scrimInFront, LockscreenWallpaper lockscreenWallpaper,
+ public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
+ LockscreenWallpaper lockscreenWallpaper, Consumer<Float> scrimBehindAlphaListener,
+ Consumer<GradientColors> scrimInFrontColorListener,
Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
AlarmManager alarmManager) {
- return new ScrimController(lightBarController, scrimBehind, scrimInFront,
- scrimVisibleListener, dozeParameters, alarmManager);
+ return new ScrimController(scrimBehind, scrimInFront, scrimBehindAlphaListener,
+ scrimInFrontColorListener, scrimVisibleListener, dozeParameters, alarmManager);
}
public NotificationIconAreaController createNotificationIconAreaController(Context context,
@@ -142,5 +145,6 @@ public class SystemUIFactory {
providers.put(NotificationViewHierarchyManager.class,
() -> new NotificationViewHierarchyManager(context));
providers.put(NotificationEntryManager.class, () -> new NotificationEntryManager(context));
+ providers.put(KeyguardDismissUtil.class, KeyguardDismissUtil::new);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 5f6c1b762c82..9ffe783fbded 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -18,12 +18,11 @@ package com.android.systemui.classifier;
public class AnglesVarianceEvaluator {
public static float evaluate(float value, int type) {
- final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
if (value > 0.20) evaluation++;
- if (value > 0.40 && !secureUnlock) evaluation++;
- if (value > 0.80 && !secureUnlock) evaluation++;
- if (value > 1.50 && !secureUnlock) evaluation++;
+ if (value > 0.40) evaluation++;
+ if (value > 0.80) evaluation++;
+ if (value > 1.50) evaluation++;
return evaluation;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 778e63092150..c39076499d08 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -109,7 +109,11 @@ public class DozeUi implements DozeMachine.Part {
switch (newState) {
case DOZE_AOD:
if (oldState == DOZE_AOD_PAUSED) {
+ // Whenever turning on the display, it's necessary to push a new frame.
+ // The display buffers will be empty and need to be filled.
mHost.dozeTimeTick();
+ // The first frame may arrive when the display isn't ready yet.
+ mHandler.postDelayed(mHost::dozeTimeTick, 100);
}
scheduleTimeTick();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 3577c0fa6180..c238e54e7cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -18,8 +18,8 @@ package com.android.systemui.fingerprint;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricDialog;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -48,7 +48,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
private FingerprintDialogView mDialogView;
private WindowManager mWindowManager;
- private IBiometricDialogReceiver mReceiver;
+ private IBiometricPromptReceiver mReceiver;
private boolean mDialogShowing;
private Handler mHandler = new Handler() {
@@ -97,7 +97,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
}
@Override
- public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
if (DEBUG) Log.d(TAG, "showFingerprintDialog");
// Remove these messages as they are part of the previous client
mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
@@ -139,7 +139,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
Log.w(TAG, "Dialog already showing");
return;
}
- mReceiver = (IBiometricDialogReceiver) args.arg2;
+ mReceiver = (IBiometricPromptReceiver) args.arg2;
mDialogView.setBundle((Bundle)args.arg1);
mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
mDialogShowing = true;
@@ -177,7 +177,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
}
if (userCanceled) {
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_USER_CANCEL);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException when hiding dialog", e);
}
@@ -193,7 +193,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
return;
}
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_NEGATIVE);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling negative button", e);
}
@@ -206,7 +206,7 @@ public class FingerprintDialogImpl extends SystemUI implements CommandQueue.Call
return;
}
try {
- mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_POSITIVE);
+ mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
} catch (RemoteException e) {
Log.e(TAG, "Remote exception when handling positive button", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 3e1ac022de61..d1d66097d48d 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -22,11 +22,12 @@ import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricDialog;
+import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
@@ -161,29 +162,29 @@ public class FingerprintDialogView extends LinearLayout {
mLastState = STATE_NONE;
updateFingerprintIcon(STATE_FINGERPRINT);
- title.setText(mBundle.getCharSequence(BiometricDialog.KEY_TITLE));
+ title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
title.setSelected(true);
- final CharSequence subtitleText = mBundle.getCharSequence(BiometricDialog.KEY_SUBTITLE);
- if (subtitleText == null) {
+ final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
+ if (TextUtils.isEmpty(subtitleText)) {
subtitle.setVisibility(View.GONE);
} else {
subtitle.setVisibility(View.VISIBLE);
subtitle.setText(subtitleText);
}
- final CharSequence descriptionText = mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION);
- if (descriptionText == null) {
- subtitle.setVisibility(View.VISIBLE);
+ final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
+ if (TextUtils.isEmpty(descriptionText)) {
description.setVisibility(View.GONE);
} else {
- description.setText(mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION));
+ description.setVisibility(View.VISIBLE);
+ description.setText(descriptionText);
}
- negative.setText(mBundle.getCharSequence(BiometricDialog.KEY_NEGATIVE_TEXT));
+ negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
final CharSequence positiveText =
- mBundle.getCharSequence(BiometricDialog.KEY_POSITIVE_TEXT);
+ mBundle.getCharSequence(BiometricPrompt.KEY_POSITIVE_TEXT);
positive.setText(positiveText); // needs to be set for marquee to work
if (positiveText != null) {
positive.setVisibility(View.VISIBLE);
@@ -269,7 +270,7 @@ public class FingerprintDialogView extends LinearLayout {
mErrorText.setTextColor(mErrorColor);
mErrorText.setContentDescription(message);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
- BiometricDialog.HIDE_DIALOG_DELAY);
+ BiometricPrompt.HIDE_DIALOG_DELAY);
}
public void showHelpMessage(String message) {
@@ -279,7 +280,7 @@ public class FingerprintDialogView extends LinearLayout {
public void showErrorMessage(String error) {
showTemporaryMessage(error);
mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
- false /* userCanceled */), BiometricDialog.HIDE_DIALOG_DELAY);
+ false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
}
private void updateFingerprintIcon(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d6e59c77af9c..426f71409095 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1184,6 +1184,10 @@ public class KeyguardViewMediator extends SystemUI {
Trace.endSection();
}
+ public boolean isHiding() {
+ return mHiding;
+ }
+
/**
* Handles SET_OCCLUDED message sent by setOccluded()
*/
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index a0bdcd00d43a..1805f96c2cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -295,6 +295,26 @@ public class PipTouchHandler {
final Rect toAdjustedBounds = mMenuState == MENU_STATE_FULL
? expandedAdjustedBounds
: normalAdjustedBounds;
+ final Rect toMovementBounds = mMenuState == MENU_STATE_FULL
+ ? expandedMovementBounds
+ : normalMovementBounds;
+
+ // If the PIP window needs to shift to right above shelf/IME and it's already above
+ // that, don't move the PIP window.
+ if (toAdjustedBounds.bottom < mMovementBounds.bottom
+ && animatingBounds.top < toAdjustedBounds.bottom) {
+ return;
+ }
+
+ // If the PIP window needs to shift down due to dismissal of shelf/IME but it's way
+ // above the position as if shelf/IME shows, don't move the PIP window.
+ int movementBoundsAdjustment = toMovementBounds.bottom - mMovementBounds.bottom;
+ int offsetAdjustment = fromImeAdjustment ? mImeOffset : mShelfHeight;
+ if (toAdjustedBounds.bottom >= mMovementBounds.bottom
+ && animatingBounds.top
+ < toAdjustedBounds.bottom - movementBoundsAdjustment - offsetAdjustment) {
+ return;
+ }
animateToOffset(animatingBounds, toAdjustedBounds);
}
@@ -320,10 +340,6 @@ public class PipTouchHandler {
private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) {
final Rect bounds = new Rect(animatingBounds);
- if (toAdjustedBounds.bottom < mMovementBounds.bottom
- && bounds.top < toAdjustedBounds.bottom) {
- return;
- }
bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
// In landscape mode, PIP window can go offset while launching IME. We want to align the
// the top of the PIP window with the top of the movement bounds in that case.
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index a70b3587f195..40ce69b8e580 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -514,7 +514,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
autoTriggerThreshold = 15;
}
- BatterySaverUtils.scheduleAutoBatterySaver(mContext, autoTriggerThreshold);
+ BatterySaverUtils.ensureAutoBatterySaver(mContext, autoTriggerThreshold);
showAutoSaverEnabledConfirmation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index bfbfbf6fe813..a9455f23e29d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -16,19 +16,19 @@
package com.android.systemui.qs;
+import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Canvas;
-import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
-import com.android.settingslib.Utils;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.statusbar.ExpandableOutlineView;
+import com.android.systemui.statusbar.CommandQueue;
/**
* Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
@@ -44,8 +44,13 @@ public class QSContainerImpl extends FrameLayout {
protected float mQsExpansion;
private QSCustomizer mQSCustomizer;
private View mQSFooter;
+
private View mBackground;
+ private View mBackgroundGradient;
+ private View mStatusBarBackground;
+
private int mSideMargins;
+ private boolean mQsDisabled;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -60,6 +65,8 @@ public class QSContainerImpl extends FrameLayout {
mQSCustomizer = findViewById(R.id.qs_customize);
mQSFooter = findViewById(R.id.qs_footer);
mBackground = findViewById(R.id.quick_settings_background);
+ mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
+ mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
setClickable(true);
@@ -68,6 +75,23 @@ public class QSContainerImpl extends FrameLayout {
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ // Hide the backgrounds when in landscape mode.
+ if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mBackgroundGradient.setVisibility(View.INVISIBLE);
+ mStatusBarBackground.setVisibility(View.INVISIBLE);
+ } else {
+ mBackgroundGradient.setVisibility(View.VISIBLE);
+ mStatusBarBackground.setVisibility(View.VISIBLE);
+ }
+
+ updateResources();
+ mSizePoint.set(0, 0); // Will be retrieved on next measure pass.
+ }
+
+ @Override
public boolean performClick() {
// Want to receive clicks so missing QQS tiles doesn't cause collapse, but
// don't want to do anything with them.
@@ -76,6 +100,16 @@ public class QSContainerImpl extends FrameLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mQsDisabled) {
+ // Only show the status bar contents in QQS header when QS is disabled.
+ mHeader.measure(widthMeasureSpec, heightMeasureSpec);
+ LayoutParams layoutParams = (LayoutParams) mHeader.getLayoutParams();
+ int height = layoutParams.topMargin + layoutParams.bottomMargin
+ + mHeader.getMeasuredHeight();
+ super.onMeasure(
+ widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ return;
+ }
// Since we control our own bottom, be whatever size we want.
// Otherwise the QSPanel ends up with 0 height when the window is only the
// size of the status bar.
@@ -90,9 +124,8 @@ public class QSContainerImpl extends FrameLayout {
// QSCustomizer will always be the height of the screen, but do this after
// other measuring to avoid changing the height of the QS.
- getDisplay().getRealSize(mSizePoint);
mQSCustomizer.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
+ MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
}
@Override
@@ -101,6 +134,23 @@ public class QSContainerImpl extends FrameLayout {
updateExpansion();
}
+ public void disable(int state1, int state2, boolean animate) {
+ final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
+ if (disabled == mQsDisabled) return;
+ mQsDisabled = disabled;
+ mBackgroundGradient.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ mQSPanel.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ mQSFooter.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ }
+
+ private void updateResources() {
+ LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
+ layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
+
+ mQSPanel.setLayoutParams(layoutParams);
+ }
+
/**
* Overrides the height of this view (post-layout), so that the content is clipped to that
* height and the background is set to that height.
@@ -147,4 +197,11 @@ public class QSContainerImpl extends FrameLayout {
lp.rightMargin = mSideMargins;
lp.leftMargin = mSideMargins;
}
+
+ private int getDisplayHeight() {
+ if (mSizePoint.y == 0) {
+ getDisplay().getRealSize(mSizePoint);
+ }
+ return mSizePoint.y;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 3f3cea2eaa17..6c7eda7c89d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -69,4 +69,6 @@ public interface QSFooter {
*/
@Nullable
View getExpandView();
+
+ default void disable(int state1, int state2, boolean animate) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 51c359a023a8..458e6480db24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -47,10 +47,8 @@ import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.R.dimen;
-import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -62,8 +60,7 @@ import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChange
import com.android.systemui.tuner.TunerService;
public class QSFooterImpl extends FrameLayout implements QSFooter,
- OnClickListener, OnUserInfoChangedListener, EmergencyListener,
- SignalCallback, CommandQueue.Callbacks {
+ OnClickListener, OnUserInfoChangedListener, EmergencyListener, SignalCallback {
private ActivityStarter mActivityStarter;
private UserInfoController mUserInfoController;
@@ -211,16 +208,9 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
}
@Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
- }
-
- @Override
@VisibleForTesting
public void onDetachedFromWindow() {
setListening(false);
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 018a63560429..cb068e3b5372 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -14,9 +14,12 @@
package com.android.systemui.qs;
+import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Fragment;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
@@ -35,12 +38,14 @@ import android.widget.FrameLayout.LayoutParams;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.R.id;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.stack.StackStateAnimator;
-public class QSFragment extends Fragment implements QS {
+public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
private static final String TAG = "QS";
private static final boolean DEBUG = false;
private static final String EXTRA_EXPANDED = "expanded";
@@ -65,6 +70,7 @@ public class QSFragment extends Fragment implements QS {
private int mLayoutDirection;
private QSFooter mFooter;
private float mLastQSExpansion = -1;
+ private boolean mQsDisabled;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@@ -176,6 +182,17 @@ public class QSFragment extends Fragment implements QS {
}
}
+ @Override
+ public void disable(int state1, int state2, boolean animate) {
+ final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
+ if (disabled == mQsDisabled) return;
+ mQsDisabled = disabled;
+ mContainer.disable(state1, state2, animate);
+ mHeader.disable(state1, state2, animate);
+ mFooter.disable(state1, state2, animate);
+ updateQsState();
+ }
+
private void updateQsState() {
final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
|| mHeaderAnimating;
@@ -189,6 +206,9 @@ public class QSFragment extends Fragment implements QS {
mFooter.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
? View.VISIBLE
: View.INVISIBLE);
+ if (mQsDisabled) {
+ mFooter.setVisibility(View.GONE);
+ }
mFooter.setExpanded((mKeyguardShowing && !mHeaderAnimating)
|| (mQsExpanded && !mStackScrollerOverscrolling));
mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
@@ -258,6 +278,12 @@ public class QSFragment extends Fragment implements QS {
mHeader.setListening(listening);
mFooter.setListening(listening);
mQSPanel.setListening(mListening && mQsExpanded);
+ if (listening) {
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+ } else {
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class)
+ .removeCallbacks(this);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 224c367b9c95..e2af90d6bbce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
@@ -54,8 +55,10 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
+import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.NextAlarmController;
import java.util.Locale;
@@ -65,7 +68,7 @@ import java.util.Locale;
* battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner
* contents.
*/
-public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue.Callbacks,
+public class QuickStatusBarHeader extends RelativeLayout implements
View.OnClickListener, NextAlarmController.NextAlarmChangeCallback {
private static final String TAG = "QuickStatusBarHeader";
private static final boolean DEBUG = false;
@@ -90,6 +93,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
+ private View mSystemIconsView;
private View mQuickQsStatusIcons;
private View mDate;
private View mHeaderTextContainerView;
@@ -107,6 +111,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
private View mStatusSeparator;
private ImageView mRingerModeIcon;
private TextView mRingerModeTextView;
+ private BatteryMeterView mBatteryMeterView;
+ private Clock mClockView;
+ private DateView mDateView;
private NextAlarmController mAlarmController;
/** Counts how many times the long press tooltip has been shown to the user. */
@@ -138,6 +145,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
mDate = findViewById(R.id.date);
mDate.setOnClickListener(this);
+ mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
@@ -164,8 +172,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
- BatteryMeterView battery = findViewById(R.id.battery);
- battery.setForceShowPercent(true);
+ mBatteryMeterView = findViewById(R.id.battery);
+ mBatteryMeterView.setForceShowPercent(true);
+ mClockView = findViewById(R.id.clock);
+ mDateView = findViewById(R.id.date);
}
private void updateStatusText() {
@@ -212,6 +222,13 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateResources();
+
+ // Update color schemes in landscape to use wallpaperTextColor
+ boolean shouldUseWallpaperTextColor =
+ newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
+ mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor);
+ mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor);
+ mDateView.useWallpaperTextColor(shouldUseWallpaperTextColor);
}
@Override
@@ -221,11 +238,22 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
}
private void updateResources() {
- // Update height, especially due to landscape mode restricting space.
+ Resources resources = mContext.getResources();
+
+ // Update height for a few views, especially due to landscape mode restricting space.
mHeaderTextContainerView.getLayoutParams().height =
- mContext.getResources().getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
+ resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height);
mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams());
+ mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
+ mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
+
+ getLayoutParams().height = resources.getDimensionPixelSize(mQsDisabled
+ ? com.android.internal.R.dimen.quick_qs_offset_height
+ : com.android.internal.R.dimen.quick_qs_total_height);
+ setLayoutParams(getLayoutParams());
+
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
}
@@ -293,20 +321,18 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
TOOLTIP_NOT_YET_SHOWN_COUNT);
}
- @Override
public void disable(int state1, int state2, boolean animate) {
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
mHeaderQsPanel.setDisabledByPolicy(disabled);
- final int rawHeight = (int) getResources().getDimension(
- com.android.internal.R.dimen.quick_qs_total_height);
- getLayoutParams().height = disabled ? (rawHeight - mHeaderQsPanel.getHeight()) : rawHeight;
+ mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
+ updateResources();
}
@Override
public void onAttachedToWindow() {
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
requestApplyInsets();
}
@@ -327,7 +353,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
@VisibleForTesting
public void onDetachedFromWindow() {
setListening(false);
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager);
super.onDetachedFromWindow();
}
@@ -497,9 +522,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue
mHeaderQsPanel.setHost(host, null /* No customization in header */);
// Use SystemUI context to get battery meter colors, and let it use the default tint (white)
- BatteryMeterView battery = findViewById(R.id.battery);
- battery.setColorsFromContext(mHost.getContext());
- battery.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
+ mBatteryMeterView.setColorsFromContext(mHost.getContext());
+ mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
}
public void setCallback(Callback qsPanelCallback) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
index 23d3ebbbfe80..24b5a34075d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
@@ -29,7 +29,6 @@ import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSPanel;
-import com.android.systemui.statusbar.car.UserGridView;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 0ee6d1fb6664..da21aa5017d3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -20,21 +20,20 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Fragment;
+import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.GridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.QSFooter;
-import com.android.systemui.statusbar.car.PageIndicator;
-import com.android.systemui.statusbar.car.UserGridView;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.car.UserGridRecyclerView;
import java.util.ArrayList;
import java.util.List;
@@ -45,14 +44,12 @@ import java.util.List;
* status bar, and a static row with access to the user switcher and settings.
*/
public class CarQSFragment extends Fragment implements QS {
- private ViewGroup mPanel;
private View mHeader;
private View mUserSwitcherContainer;
private CarQSFooter mFooter;
private View mFooterUserName;
private View mFooterExpandIcon;
- private UserGridView mUserGridView;
- private PageIndicator mPageIndicator;
+ private UserGridRecyclerView mUserGridView;
private AnimatorSet mAnimatorSet;
private UserSwitchCallback mUserSwitchCallback;
@@ -65,7 +62,6 @@ public class CarQSFragment extends Fragment implements QS {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mPanel = (ViewGroup) view;
mHeader = view.findViewById(R.id.header);
mFooter = view.findViewById(R.id.qs_footer);
mFooterUserName = mFooter.findViewById(R.id.user_name);
@@ -75,16 +71,15 @@ public class CarQSFragment extends Fragment implements QS {
updateUserSwitcherHeight(0);
- mUserGridView = view.findViewById(R.id.user_grid);
- mUserGridView.init(null, Dependency.get(UserSwitcherController.class),
- false /* overrideAlpha */);
-
- mPageIndicator = view.findViewById(R.id.user_switcher_page_indicator);
- mPageIndicator.setupWithViewPager(mUserGridView);
+ Context context = getContext();
+ mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
+ GridLayoutManager layoutManager = new GridLayoutManager(context,
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.buildAdapter();
mUserSwitchCallback = new UserSwitchCallback();
mFooter.setUserSwitchCallback(mUserSwitchCallback);
- mUserGridView.setUserSwitchCallback(mUserSwitchCallback);
}
@Override
@@ -111,13 +106,11 @@ public class CarQSFragment extends Fragment implements QS {
@Override
public void setHeaderListening(boolean listening) {
mFooter.setListening(listening);
- mUserGridView.setListening(listening);
}
@Override
public void setListening(boolean listening) {
mFooter.setListening(listening);
- mUserGridView.setListening(listening);
}
@Override
@@ -219,24 +212,6 @@ public class CarQSFragment extends Fragment implements QS {
mShowing = false;
animateHeightChange(false /* opening */);
}
-
- public void resetShowing() {
- if (mShowing) {
- for (int i = 0; i < mUserGridView.getChildCount(); i++) {
- ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i);
- // Need to bring the last child to the front to maintain the order in the pod
- // container. Why? ¯\_(ツ)_/¯
- if (podContainer.getChildCount() > 0) {
- podContainer.getChildAt(podContainer.getChildCount() - 1).bringToFront();
- }
- // The alpha values are default to 0, so if the pods have been refreshed, they
- // need to be set to 1 when showing.
- for (int j = 0; j < podContainer.getChildCount(); j++) {
- podContainer.getChildAt(j).setAlpha(1f);
- }
- }
- }
- }
}
private void updateUserSwitcherHeight(int height) {
@@ -260,27 +235,6 @@ public class CarQSFragment extends Fragment implements QS {
});
allAnimators.add(heightAnimator);
- // The user grid contains pod containers that each contain a number of pods. Animate
- // all pods to avoid any discrepancy/race conditions with possible changes during the
- // animation.
- int cascadeDelay = getResources().getInteger(
- R.integer.car_user_switcher_anim_cascade_delay_ms);
- for (int i = 0; i < mUserGridView.getChildCount(); i++) {
- ViewGroup podContainer = (ViewGroup) mUserGridView.getChildAt(i);
- for (int j = 0; j < podContainer.getChildCount(); j++) {
- View pod = podContainer.getChildAt(j);
- Animator podAnimator = AnimatorInflater.loadAnimator(getContext(),
- opening ? R.anim.car_user_switcher_open_pod_animation
- : R.anim.car_user_switcher_close_pod_animation);
- // Add the cascading delay between pods
- if (opening) {
- podAnimator.setStartDelay(podAnimator.getStartDelay() + j * cascadeDelay);
- }
- podAnimator.setTarget(pod);
- allAnimators.add(podAnimator);
- }
- }
-
Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(),
opening ? R.anim.car_user_switcher_open_name_animation
: R.anim.car_user_switcher_close_name_animation);
@@ -293,12 +247,6 @@ public class CarQSFragment extends Fragment implements QS {
iconAnimator.setTarget(mFooterExpandIcon);
allAnimators.add(iconAnimator);
- Animator pageAnimator = AnimatorInflater.loadAnimator(getContext(),
- opening ? R.anim.car_user_switcher_open_pages_animation
- : R.anim.car_user_switcher_close_pages_animation);
- pageAnimator.setTarget(mPageIndicator);
- allAnimators.add(pageAnimator);
-
mAnimatorSet = new AnimatorSet();
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
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 7dcf5c0c3b35..4b312f533024 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -209,7 +209,7 @@ public class DndTile extends QSTileImpl<BooleanState> {
state.slash.isSlashed = !state.value;
state.label = getTileLabel();
state.secondaryLabel = ZenModeConfig.getDescription(mContext,zen != Global.ZEN_MODE_OFF,
- mController.getConfig());
+ mController.getConfig(), false);
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0f85c5b37f65..8bb3c0231a76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.ActivityManager;
+import android.app.trust.TrustManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -51,6 +52,7 @@ import com.android.systemui.EventLogTags;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
+import com.android.systemui.SystemUIApplication;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
@@ -70,6 +72,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -107,6 +110,7 @@ public class Recents extends SystemUI
private Handler mHandler;
private RecentsImpl mImpl;
+ private TrustManager mTrustManager;
private int mDraggingInRecentsCurrentUser;
// Only For system user, this is the callbacks instance we return to each secondary user
@@ -235,6 +239,8 @@ public class Recents extends SystemUI
registerWithSystemUser();
}
putComponent(Recents.class, this);
+
+ mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
}
@Override
@@ -342,12 +348,28 @@ public class Recents extends SystemUI
// If connected to launcher service, let it handle the toggle logic
IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
if (overviewProxy != null) {
- try {
- overviewProxy.onOverviewToggle();
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+ final Runnable toggleRecents = () -> {
+ try {
+ if (mOverviewProxyService.getProxy() != null) {
+ mOverviewProxyService.getProxy().onOverviewToggle();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+ }
+ };
+ // Preload only if device for current user is unlocked
+ final StatusBar statusBar = getComponent(StatusBar.class);
+ if (statusBar != null && statusBar.isKeyguardShowing()) {
+ statusBar.executeRunnableDismissingKeyguard(() -> {
+ // Flush trustmanager before checking device locked per user
+ mTrustManager.reportKeyguardShowingChanged();
+ mHandler.post(toggleRecents);
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */,
+ true /* deferred */);
+ } else {
+ toggleRecents.run();
}
+ return;
}
int growTarget = getComponent(Divider.class).getView().growsRecents();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 75bc95588244..30e9afd8ea04 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import android.annotation.TargetApi;
import android.app.ActivityManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -62,6 +61,7 @@ public class RecentsOnboarding {
private static final String TAG = "RecentsOnboarding";
private static final boolean RESET_PREFS_FOR_DEBUG = false;
+ private static final boolean ONBOARDING_ENABLED = false;
private static final long SHOW_DELAY_MS = 500;
private static final long SHOW_HIDE_DURATION_MS = 300;
// Don't show the onboarding until the user has launched this number of apps.
@@ -184,6 +184,9 @@ public class RecentsOnboarding {
}
public void onConnectedToLauncher() {
+ if (!ONBOARDING_ENABLED) {
+ return;
+ }
boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext,
Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
if (!mTaskListenerRegistered && !alreadySeenRecentsOnboarding) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 3dd6e353c924..bfbba7c1128a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -107,7 +107,7 @@ public class ScreenPinningRequest implements View.OnClickListener {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 65037f99ab30..6fd0aa6330f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,7 @@ package com.android.systemui.statusbar;
import android.content.ComponentName;
import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -160,7 +160,7 @@ public class CommandQueue extends IStatusBar.Stub {
default void onRotationProposal(int rotation, boolean isValid) { }
- default void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) { }
+ default void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) { }
default void onFingerprintAuthenticated() { }
default void onFingerprintHelp(String message) { }
default void onFingerprintError(String error) { }
@@ -513,7 +513,7 @@ public class CommandQueue extends IStatusBar.Stub {
}
@Override
- public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+ public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = bundle;
@@ -759,7 +759,7 @@ public class CommandQueue extends IStatusBar.Stub {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showFingerprintDialog(
(Bundle)((SomeArgs)msg.obj).arg1,
- (IBiometricDialogReceiver)((SomeArgs)msg.obj).arg2);
+ (IBiometricPromptReceiver)((SomeArgs)msg.obj).arg2);
}
break;
case MSG_FINGERPRINT_AUTHENTICATED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3ece2f958100..87e6608a576a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
@@ -100,13 +101,17 @@ import java.util.function.Consumer;
public class ExpandableNotificationRow extends ActivatableNotificationView
implements PluginListener<NotificationMenuRowPlugin> {
+ private static final boolean DEBUG = false;
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
private static final int MENU_VIEW_INDEX = 0;
private static final String TAG = "ExpandableNotifRow";
+ /**
+ * Listener for when {@link ExpandableNotificationRow} is laid out.
+ */
public interface LayoutListener {
- public void onLayout();
+ void onLayout();
}
private LayoutListener mLayoutListener;
@@ -174,8 +179,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
- private PackageManager mCachedPackageManager;
- private PackageInfo mCachedPackageInfo;
+ /**
+ * Whether or not this row represents a system notification. Note that if this is {@code null},
+ * that means we were either unable to retrieve the info or have yet to retrieve the info.
+ */
+ private Boolean mIsSystemNotification;
private String mAppName;
private boolean mIsHeadsUp;
private boolean mLastChronometerRunning = true;
@@ -271,7 +279,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public Float get(ExpandableNotificationRow object) {
return object.getTranslation();
}
- };
+ };
private OnClickListener mOnClickListener;
private boolean mHeadsupDisappearRunning;
private View mChildAfterViewWhenDismissed;
@@ -292,6 +300,33 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private int mNotificationColorAmbient;
private NotificationViewState mNotificationViewState;
+ private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
+ new SystemNotificationAsyncTask();
+
+ /**
+ * Returns whether the given {@code statusBarNotification} is a system notification.
+ * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
+ * calls.
+ */
+ private static Boolean isSystemNotification(
+ Context context, StatusBarNotification statusBarNotification) {
+ PackageManager packageManager = StatusBar.getPackageManagerForUser(
+ context, statusBarNotification.getUser().getIdentifier());
+ Boolean isSystemNotification = null;
+
+ try {
+ PackageInfo packageInfo = packageManager.getPackageInfo(
+ statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
+
+ isSystemNotification =
+ com.android.settingslib.Utils.isSystemPackage(
+ context.getResources(), packageManager, packageInfo);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
+ }
+ return isSystemNotification;
+ }
+
@Override
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -383,45 +418,43 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mStatusBarNotification = entry.notification;
mNotificationInflater.inflateNotificationViews();
- perhapsCachePackageInfo();
+ cacheIsSystemNotification();
}
/**
- * Caches the package manager and info objects which are expensive to obtain.
+ * Caches whether or not this row contains a system notification. Note, this is only cached
+ * once per notification as the packageInfo can't technically change for a notification row.
*/
- private void perhapsCachePackageInfo() {
- if (mCachedPackageInfo == null) {
- mCachedPackageManager = StatusBar.getPackageManagerForUser(
- mContext, mStatusBarNotification.getUser().getIdentifier());
- try {
- mCachedPackageInfo = mCachedPackageManager.getPackageInfo(
- mStatusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "perhapsCachePackageInfo: Could not find package info");
+ private void cacheIsSystemNotification() {
+ if (mIsSystemNotification == null) {
+ if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
+ // Run async task once, only if it hasn't already been executed. Note this is
+ // executed in serial - no need to parallelize this small task.
+ mSystemNotificationAsyncTask.execute();
}
}
}
/**
- * Returns whether this row is considered non-blockable (e.g. it's a non-blockable system notif,
- * covers multiple channels, or is in a whitelist).
+ * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif
+ * or is in a whitelist).
*/
public boolean getIsNonblockable() {
- boolean isNonblockable;
-
- isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
+ boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
.isNonblockablePackage(mStatusBarNotification.getPackageName());
- // Only bother with going through the children if the row is still blockable based on the
- // number of unique channels.
- if (!isNonblockable) {
- isNonblockable = getNumUniqueChannels() > 1;
+ // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
+ // again, but in-place on the main thread this time. This should rarely ever get called.
+ if (mIsSystemNotification == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Retrieving isSystemNotification on main thread");
+ }
+ mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
+ mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
}
- // Only bother with IPC if the package is still blockable.
- if (!isNonblockable && mCachedPackageManager != null && mCachedPackageInfo != null) {
- if (com.android.settingslib.Utils.isSystemPackage(
- mContext.getResources(), mCachedPackageManager, mCachedPackageInfo)) {
+ if (!isNonblockable && mIsSystemNotification != null) {
+ if (mIsSystemNotification) {
if (mEntry.channel != null
&& !mEntry.channel.isBlockableSystem()) {
isNonblockable = true;
@@ -2828,4 +2861,21 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*/
boolean onClick(View v, int x, int y, MenuItem item);
}
+
+ /**
+ * Background task for executing IPCs to check if the notification is a system notification. The
+ * output is used for both the blocking helper and the notification info.
+ */
+ private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
+
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ return isSystemNotification(mContext, mStatusBarNotification);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ mIsSystemNotification = result;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index b81e9af4f692..29c2edc22f4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -26,6 +26,7 @@ import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
@@ -1631,6 +1632,42 @@ public class NotificationContentView extends FrameLayout {
return null;
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ float y = ev.getY();
+ // We still want to distribute touch events to the remote input even if it's outside the
+ // view boundary. We're therefore manually dispatching these events to the remote view
+ RemoteInputView riv = getRemoteInputForView(getViewForVisibleType(mVisibleType));
+ if (riv != null && riv.getVisibility() == VISIBLE) {
+ int inputStart = mUnrestrictedContentHeight - riv.getHeight();
+ if (y <= mUnrestrictedContentHeight && y >= inputStart) {
+ ev.offsetLocation(0, -inputStart);
+ return riv.dispatchTouchEvent(ev);
+ }
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
+ /**
+ * Overridden to make sure touches to the reply action bar actually go through to this view
+ */
+ @Override
+ public boolean pointInView(float localX, float localY, float slop) {
+ float top = mClipTopAmount;
+ float bottom = mUnrestrictedContentHeight;
+ return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
+ localY < (bottom + slop);
+ }
+
+ private RemoteInputView getRemoteInputForView(View child) {
+ if (child == mExpandedChild) {
+ return mExpandedRemoteInput;
+ } else if (child == mHeadsUpChild) {
+ return mHeadsUpRemoteInput;
+ }
+ return null;
+ }
+
public int getExpandHeight() {
int viewType = VISIBLE_TYPE_EXPANDED;
if (mExpandedChild == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index a93be00ba080..81dd9e8c3d87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -23,6 +23,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -34,10 +35,12 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -63,10 +66,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private INotificationManager mINotificationManager;
private PackageManager mPm;
- private String mPkg;
+ private String mPackageName;
private String mAppName;
private int mAppUid;
- private int mNumNotificationChannels;
+ private int mNumUniqueChannelsInRow;
private NotificationChannel mSingleNotificationChannel;
private int mStartingUserImportance;
private int mChosenImportance;
@@ -87,7 +90,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private OnClickListener mOnKeepShowing = this::closeControls;
- private OnClickListener mOnStopMinNotifications = v -> {
+ private OnClickListener mOnStopOrMinimizeNotifications = v -> {
swapContent(false);
};
@@ -120,16 +123,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
final INotificationManager iNotificationManager,
final String pkg,
final NotificationChannel notificationChannel,
- final int numChannels,
+ final int numUniqueChannelsInRow,
final StatusBarNotification sbn,
final CheckSaveListener checkSaveListener,
final OnSettingsClickListener onSettingsClick,
final OnAppSettingsClickListener onAppSettingsClick,
boolean isNonblockable)
throws RemoteException {
- bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
- checkSaveListener, onSettingsClick, onAppSettingsClick, isNonblockable,
- false /* isBlockingHelper */,
+ bindNotification(pm, iNotificationManager, pkg, notificationChannel,
+ numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
+ onAppSettingsClick, isNonblockable, false /* isBlockingHelper */,
false /* isUserSentimentNegative */);
}
@@ -138,7 +141,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
INotificationManager iNotificationManager,
String pkg,
NotificationChannel notificationChannel,
- int numChannels,
+ int numUniqueChannelsInRow,
StatusBarNotification sbn,
CheckSaveListener checkSaveListener,
OnSettingsClickListener onSettingsClick,
@@ -148,12 +151,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean isUserSentimentNegative)
throws RemoteException {
mINotificationManager = iNotificationManager;
- mPkg = pkg;
- mNumNotificationChannels = numChannels;
+ mPackageName = pkg;
+ mNumUniqueChannelsInRow = numUniqueChannelsInRow;
mSbn = sbn;
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
- mAppName = mPkg;
+ mAppName = mPackageName;
mCheckSaveListener = checkSaveListener;
mOnSettingsClickListener = onSettingsClick;
mSingleNotificationChannel = notificationChannel;
@@ -167,11 +170,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
- if (mNumNotificationChannels == 0) {
+ if (mNumUniqueChannelsInRow == 0) {
throw new IllegalArgumentException("bindNotification requires at least one channel");
} else {
// Special behavior for the Default channel if no other channels have been defined.
- mIsSingleDefaultChannel = mNumNotificationChannels == 1
+ mIsSingleDefaultChannel = mNumUniqueChannelsInRow == 1
&& mSingleNotificationChannel.getId().equals(
NotificationChannel.DEFAULT_CHANNEL_ID)
&& numTotalChannels == 1;
@@ -187,7 +190,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
Drawable pkgicon = null;
ApplicationInfo info;
try {
- info = mPm.getApplicationInfo(mPkg,
+ info = mPm.getApplicationInfo(
+ mPackageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -208,7 +212,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
final NotificationChannelGroup notificationChannelGroup =
mINotificationManager.getNotificationChannelGroupForPackage(
- mSingleNotificationChannel.getGroup(), mPkg, mAppUid);
+ mSingleNotificationChannel.getGroup(), mPackageName, mAppUid);
if (notificationChannelGroup != null) {
groupName = notificationChannelGroup.getName();
}
@@ -232,7 +236,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
settingsButton.setOnClickListener(
(View view) -> {
mOnSettingsClickListener.onClick(view,
- mNumNotificationChannels > 1 ? null : mSingleNotificationChannel,
+ mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
});
} else {
@@ -248,7 +252,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
} else {
if (mNegativeUserSentiment) {
blockPrompt.setText(R.string.inline_blocking_helper);
- } else if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+ } else if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
blockPrompt.setText(R.string.inline_keep_showing_app);
} else {
blockPrompt.setText(R.string.inline_keep_showing);
@@ -258,7 +262,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private void bindName() {
final TextView channelName = findViewById(R.id.channel_name);
- if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+ if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
channelName.setVisibility(View.GONE);
} else {
channelName.setText(mSingleNotificationChannel.getName());
@@ -270,19 +274,26 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
private void saveImportance() {
- if (mIsNonblockable) {
- return;
+ if (!mIsNonblockable) {
+ if (mCheckSaveListener != null) {
+ mCheckSaveListener.checkSave(this::updateImportance, mSbn);
+ } else {
+ updateImportance();
+ }
}
+ }
+
+ /**
+ * Commits the updated importance values on the background thread.
+ */
+ private void updateImportance() {
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
mChosenImportance - mStartingUserImportance);
- mSingleNotificationChannel.setImportance(mChosenImportance);
- mSingleNotificationChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- try {
- mINotificationManager.updateNotificationChannelForPackage(
- mPkg, mAppUid, mSingleNotificationChannel);
- } catch (RemoteException e) {
- // :(
- }
+
+ Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
+ bgHandler.post(new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
+ mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
+ mStartingUserImportance, mChosenImportance));
}
private void bindButtons() {
@@ -292,9 +303,9 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
View minimize = findViewById(R.id.minimize);
findViewById(R.id.undo).setOnClickListener(mOnUndo);
- block.setOnClickListener(mOnStopMinNotifications);
+ block.setOnClickListener(mOnStopOrMinimizeNotifications);
keep.setOnClickListener(mOnKeepShowing);
- minimize.setOnClickListener(mOnStopMinNotifications);
+ minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
if (mIsNonblockable) {
keep.setText(R.string.notification_done);
@@ -308,15 +319,15 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
minimize.setVisibility(GONE);
}
- // Set up app settings link
+ // Set up app settings link (i.e. Customize)
TextView settingsLinkView = findViewById(R.id.app_settings);
- Intent settingsIntent = getAppSettingsIntent(mPm, mPkg, mSingleNotificationChannel,
+ Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName, mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
- if (settingsIntent != null
+ if (!mIsForBlockingHelper
+ && settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(VISIBLE);
- settingsLinkView.setText(mContext.getString(R.string.notification_app_settings,
- mSbn.getNotification().getSettingsText()));
+ settingsLinkView.setText(mContext.getString(R.string.notification_app_settings));
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
@@ -415,12 +426,25 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
return intent;
}
+ /**
+ * Closes the controls and commits the updated importance values (indirectly). If this view is
+ * being used to show the blocking helper, this will immediately dismiss the blocking helper and
+ * commit the updated importance.
+ *
+ * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
+ * user does not have the ability to undo the action anymore. See {@link #swapContent(boolean)}
+ * for where undo is handled.
+ */
@VisibleForTesting
void closeControls(View v) {
if (mIsForBlockingHelper) {
NotificationBlockingHelperManager manager =
Dependency.get(NotificationBlockingHelperManager.class);
manager.dismissCurrentBlockingHelper();
+
+ // Since this won't get a callback via gutsContainer.closeControls, save the new
+ // importance values immediately.
+ saveImportance();
} else {
int[] parentLoc = new int[2];
int[] targetLoc = new int[2];
@@ -454,11 +478,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// Save regardless of the importance so we can lock the importance field if the user wants
// to keep getting notifications
if (save) {
- if (mCheckSaveListener != null) {
- mCheckSaveListener.checkSave(this::saveImportance, mSbn);
- } else {
- saveImportance();
- }
+ saveImportance();
}
return false;
}
@@ -467,4 +487,48 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public int getActualHeight() {
return getHeight();
}
+
+ /**
+ * Runnable to either update the given channel (with a new importance value) or, if no channel
+ * is provided, update notifications enabled state for the package.
+ */
+ private static class UpdateImportanceRunnable implements Runnable {
+ private final INotificationManager mINotificationManager;
+ private final String mPackageName;
+ private final int mAppUid;
+ private final @Nullable NotificationChannel mChannelToUpdate;
+ private final int mCurrentImportance;
+ private final int mNewImportance;
+
+
+ public UpdateImportanceRunnable(INotificationManager notificationManager,
+ String packageName, int appUid, @Nullable NotificationChannel channelToUpdate,
+ int currentImportance, int newImportance) {
+ mINotificationManager = notificationManager;
+ mPackageName = packageName;
+ mAppUid = appUid;
+ mChannelToUpdate = channelToUpdate;
+ mCurrentImportance = currentImportance;
+ mNewImportance = newImportance;
+ }
+
+ @Override
+ public void run() {
+ try {
+ if (mChannelToUpdate != null) {
+ mChannelToUpdate.setImportance(mNewImportance);
+ mChannelToUpdate.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ mINotificationManager.updateNotificationChannelForPackage(
+ mPackageName, mAppUid, mChannelToUpdate);
+ } else {
+ // For notifications with more than one channel, update notification enabled
+ // state. If the importance was lowered, we disable notifications.
+ mINotificationManager.setNotificationsEnabledForPackage(
+ mPackageName, mAppUid, mNewImportance >= mCurrentImportance);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to update notification importance", e);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index ccabb79e229b..e24bf6762b4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -47,7 +47,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.List;
/**
* Handles keeping track of the current user, profiles, and various things related to hiding
@@ -352,7 +351,8 @@ public class NotificationLockscreenUserManager implements Dumpable {
final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
- final boolean allowedByDpm = adminAllowsUnredactedNotifications(userHandle);
+ final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+ DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
final boolean allowed = allowedByUser && allowedByDpm;
mUsersAllowingPrivateNotifications.append(userHandle, allowed);
return allowed;
@@ -361,13 +361,13 @@ public class NotificationLockscreenUserManager implements Dumpable {
return mUsersAllowingPrivateNotifications.get(userHandle);
}
- private boolean adminAllowsUnredactedNotifications(int userHandle) {
+ private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
if (userHandle == UserHandle.USER_ALL) {
return true;
}
- final int dpmFlags = mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */,
- userHandle);
- return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) == 0;
+ final int dpmFlags =
+ mDevicePolicyManager.getKeyguardDisabledFeatures(null /* admin */, userHandle);
+ return (dpmFlags & feature) == 0;
}
/**
@@ -389,14 +389,17 @@ public class NotificationLockscreenUserManager implements Dumpable {
* "public" (secure & locked) mode?
*/
private boolean userAllowsNotificationsInPublic(int userHandle) {
- if (isCurrentProfile(userHandle)) {
+ if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
return true;
}
if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
- final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ final boolean allowedByUser = 0 != Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+ final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
+ DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+ final boolean allowed = allowedByUser && allowedByDpm;
mUsersAllowingNotifications.append(userHandle, allowed);
return allowed;
}
@@ -428,7 +431,6 @@ public class NotificationLockscreenUserManager implements Dumpable {
Notification.VISIBILITY_PRIVATE;
}
-
private void updateCurrentProfilesCache() {
synchronized (mCurrentProfiles) {
mCurrentProfiles.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 852239a2143b..abc261e6bbf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -172,6 +172,14 @@ public class NotificationMediaManager implements Dumpable {
}
}
+ if (mediaNotification != null) {
+ mMediaNotificationKey = mediaNotification.notification.getKey();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ + mMediaNotificationKey + " controller=" + mMediaController);
+ }
+ }
+
if (controller != null && !sameSessions(mMediaController, controller)) {
// We have a new media session
clearCurrentMediaNotification();
@@ -183,13 +191,6 @@ public class NotificationMediaManager implements Dumpable {
+ mMediaMetadata);
}
- if (mediaNotification != null) {
- mMediaNotificationKey = mediaNotification.notification.getKey();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
- + mMediaNotificationKey + " controller=" + mMediaController);
- }
- }
metaDataChanged = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0112661cf9fc..6364f5b63e88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar;
import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE;
-import static com.android.systemui.statusbar.phone.NotificationIconContainer.OVERFLOW_EARLY_AMOUNT;
import android.content.Context;
import android.content.res.Configuration;
@@ -26,6 +25,7 @@ import android.graphics.Rect;
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.MathUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -58,6 +58,8 @@ public class NotificationShelf extends ActivatableNotificationView implements
= SystemProperties.getBoolean("debug.icon_scroll_animations", true);
private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
private static final String TAG = "NotificationShelf";
+ private static final long SHELF_IN_TRANSLATION_DURATION = 220;
+
private ViewInvertHelper mViewInvertHelper;
private boolean mDark;
private NotificationIconContainer mShelfIcons;
@@ -65,6 +67,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
private int[] mTmp = new int[2];
private boolean mHideBackground;
private int mIconAppearTopPadding;
+ private int mShelfAppearTranslation;
private int mStatusBarHeight;
private int mStatusBarPaddingStart;
private AmbientState mAmbientState;
@@ -120,6 +123,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start);
mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
+ mShelfAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation);
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = res.getDimensionPixelOffset(R.dimen.notification_shelf_height);
@@ -151,6 +155,18 @@ public class NotificationShelf extends ActivatableNotificationView implements
updateInteractiveness();
}
+ public void fadeInTranslating() {
+ float translation = mShelfIcons.getTranslationY();
+ mShelfIcons.setTranslationY(translation + mShelfAppearTranslation);
+ mShelfIcons.setAlpha(0);
+ mShelfIcons.animate()
+ .alpha(1)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
+ .translationY(translation)
+ .setDuration(SHELF_IN_TRANSLATION_DURATION)
+ .start();
+ }
+
@Override
protected View getContentView() {
return mShelfIcons;
@@ -175,12 +191,14 @@ public class NotificationShelf extends ActivatableNotificationView implements
float viewEnd = lastViewState.yTranslation + lastViewState.height;
mShelfState.copyFrom(lastViewState);
mShelfState.height = getIntrinsicHeight();
- mShelfState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
+
+ float awakenTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
getFullyClosedTranslation());
+ float darkTranslation = mAmbientState.getDarkTopPadding();
+ float yRatio = mAmbientState.hasPulsingNotifications() ?
+ 0 : mAmbientState.getDarkAmount();
+ mShelfState.yTranslation = MathUtils.lerp(awakenTranslation, darkTranslation, yRatio);
mShelfState.zTranslation = ambientState.getBaseZHeight();
- if (mAmbientState.isDark() && !mAmbientState.hasPulsingNotifications()) {
- mShelfState.yTranslation = mAmbientState.getDarkTopPadding();
- }
float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation())
/ (getIntrinsicHeight() * 2);
openedAmount = Math.min(1.0f, openedAmount);
@@ -555,7 +573,9 @@ public class NotificationShelf extends ActivatableNotificationView implements
iconState.translateContent = false;
}
float transitionAmount;
- if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
+ if (mAmbientState.getDarkAmount() > 0 && !row.isInShelf()) {
+ transitionAmount = mAmbientState.isFullyDark() ? 1 : 0;
+ } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
|| iconState.useLinearTransitionAmount) {
transitionAmount = iconTransitionAmount;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index fd3a9d5e2bd4..1637849d79ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -323,8 +323,7 @@ public class NotificationViewHierarchyManager {
boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
.notification);
if (suppressedSummary
- || (mLockscreenUserManager.isLockscreenPublicMode(userId)
- && !mLockscreenUserManager.shouldShowLockscreenNotifications())
+ || mLockscreenUserManager.shouldHideNotifications(userId)
|| (isLocked && !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index b7620f30d742..51b42395e369 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -141,12 +142,14 @@ public class StatusBarMobileView extends AlphaOptimizedLinearLayout implements D
if (mState.strengthId != state.strengthId) {
mMobileDrawable.setLevel(state.strengthId);
}
- if (mState.typeId != state.typeId && state.typeId != 0) {
- mMobileType.setContentDescription(state.typeContentDescription);
- mMobileType.setImageResource(state.typeId);
- mMobileType.setVisibility(View.VISIBLE);
- } else {
- mMobileType.setVisibility(View.GONE);
+ if (mState.typeId != state.typeId) {
+ if (state.typeId != 0) {
+ mMobileType.setContentDescription(state.typeContentDescription);
+ mMobileType.setImageResource(state.typeId);
+ mMobileType.setVisibility(View.VISIBLE);
+ } else {
+ mMobileType.setVisibility(View.GONE);
+ }
}
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
@@ -161,6 +164,9 @@ public class StatusBarMobileView extends AlphaOptimizedLinearLayout implements D
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ if (!isInArea(area, this)) {
+ return;
+ }
mMobileDrawable.setDarkIntensity(darkIntensity);
ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
mIn.setImageTintList(color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index afd373ed6321..62cd16fca3bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -175,6 +176,9 @@ public class StatusBarWifiView extends AlphaOptimizedLinearLayout implements Dar
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ if (!isInArea(area, this)) {
+ return;
+ }
mDarkIntensity = darkIntensity;
Drawable d = mWifiIcon.getDrawable();
if (d instanceof NeutralGoodDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 5f3e2e358306..7285db659f3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -42,6 +42,11 @@ public class CarFacetButton extends LinearLayout {
/** App packages that are allowed to be used with this widget */
private String[] mFacetPackages;
private int mIconResourceId;
+ /**
+ * If defined in the xml this will be the icon that's rendered when the button is marked as
+ * selected
+ */
+ private int mSelectedIconResourceId;
private boolean mUseMoreIcon = true;
private float mSelectedAlpha = 1f;
private float mUnselectedAlpha = 1f;
@@ -112,10 +117,9 @@ public class CarFacetButton extends LinearLayout {
mIcon.setClickable(false);
mIcon.setAlpha(mUnselectedAlpha);
mIconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
- if (mIconResourceId == 0) {
- throw new RuntimeException("specified icon resource was not found and is required");
- }
mIcon.setImageResource(mIconResourceId);
+ mSelectedIconResourceId = styledAttributes.getResourceId(
+ R.styleable.CarFacetButton_selectedIcon, mIconResourceId);
mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
mMoreIcon.setClickable(false);
@@ -161,22 +165,10 @@ public class CarFacetButton extends LinearLayout {
*/
public void setSelected(boolean selected, boolean showMoreIcon) {
mSelected = selected;
- if (selected) {
- if (mUseMoreIcon) {
- mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
- }
- mIcon.setAlpha(mSelectedAlpha);
- } else {
- mMoreIcon.setVisibility(GONE);
- mIcon.setAlpha(mUnselectedAlpha);
- }
- }
-
- public void setIcon(Drawable d) {
- if (d != null) {
- mIcon.setImageDrawable(d);
- } else {
- mIcon.setImageResource(mIconResourceId);
+ mIcon.setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha);
+ mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId);
+ if (mUseMoreIcon) {
+ mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index e73b1736f33a..b2cef16277f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -25,7 +25,9 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
/**
* A custom navigation bar for the automotive use case.
@@ -52,6 +54,17 @@ class CarNavigationBarView extends LinearLayout {
if (mNotificationsButton != null) {
mNotificationsButton.setOnClickListener(this::onNotificationsClick);
}
+ View mStatusIcons = findViewById(R.id.statusIcons);
+ if (mStatusIcons != null) {
+ // Attach the controllers for Status icons such as wifi and bluetooth if the standard
+ // container is in the view.
+ StatusBarIconController.DarkIconManager mDarkIconManager =
+ new StatusBarIconController.DarkIconManager(
+ mStatusIcons.findViewById(R.id.statusIcons));
+ mDarkIconManager.setShouldLog(true);
+ Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
+ }
+
}
void setStatusBar(CarStatusBar carStatusBar) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 0cdaec1432c7..ec243fe98710 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.util.Log;
import android.widget.ImageView;
import com.android.systemui.R;
@@ -17,23 +18,34 @@ import java.net.URISyntaxException;
*/
public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImageButton {
- private static final float SELECTED_ALPHA = 1;
- private static final float UNSELECTED_ALPHA = 0.7f;
-
+ private static final String TAG = "CarNavigationButton";
private Context mContext;
- private String mIntent = null;
- private String mLongIntent = null;
- private boolean mBroadcastIntent = false;
+ private String mIntent;
+ private String mLongIntent;
+ private boolean mBroadcastIntent;
private boolean mSelected = false;
+ private float mSelectedAlpha = 1f;
+ private float mUnselectedAlpha = 1f;
+ private int mSelectedIconResourceId;
+ private int mIconResourceId;
public CarNavigationButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarNavigationButton);
+ TypedArray typedArray = context.obtainStyledAttributes(
+ attrs, R.styleable.CarNavigationButton);
mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent);
mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent);
mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false);
+ mSelectedAlpha = typedArray.getFloat(
+ R.styleable.CarNavigationButton_selectedAlpha, mSelectedAlpha);
+ mUnselectedAlpha = typedArray.getFloat(
+ R.styleable.CarNavigationButton_unselectedAlpha, mUnselectedAlpha);
+ mIconResourceId = typedArray.getResourceId(
+ com.android.internal.R.styleable.ImageView_src, 0);
+ mSelectedIconResourceId = typedArray.getResourceId(
+ R.styleable.CarNavigationButton_selectedIcon, mIconResourceId);
}
@@ -45,17 +57,20 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag
public void onFinishInflate() {
super.onFinishInflate();
setScaleType(ImageView.ScaleType.CENTER);
- setAlpha(UNSELECTED_ALPHA);
+ setAlpha(mUnselectedAlpha);
try {
if (mIntent != null) {
final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
setOnClickListener(v -> {
- if (mBroadcastIntent) {
- mContext.sendBroadcast(intent);
- return;
+ try {
+ if (mBroadcastIntent) {
+ mContext.sendBroadcast(intent);
+ return;
+ }
+ mContext.startActivity(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to launch intent", e);
}
- mContext.startActivity(intent);
});
}
} catch (URISyntaxException e) {
@@ -65,9 +80,13 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag
try {
if (mLongIntent != null) {
final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
setOnLongClickListener(v -> {
- mContext.startActivity(intent);
+ try {
+ mContext.startActivity(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to launch intent", e);
+ }
+ // consume event either way
return true;
});
}
@@ -82,6 +101,7 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag
public void setSelected(boolean selected) {
super.setSelected(selected);
mSelected = selected;
- setAlpha(mSelected ? SELECTED_ALPHA : UNSELECTED_ALPHA);
+ setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha);
+ setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3fb11376f6f4..008794c1c05a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -418,8 +418,7 @@ public class CarStatusBar extends StatusBar implements
Dependency.get(UserSwitcherController.class);
if (userSwitcherController.useFullscreenUserSwitcher()) {
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
- userSwitcherController,
- mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
+ mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
} else {
super.createUserSwitcher();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index bc353f2dc0f9..fb525f736f26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,14 +18,15 @@ package com.android.systemui.statusbar.car;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.content.res.Resources;
+import android.content.Context;
import android.view.View;
import android.view.ViewStub;
import android.widget.ProgressBar;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
/**
* Manages the fullscreen user switcher.
@@ -33,36 +34,25 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
public class FullscreenUserSwitcher {
private final View mContainer;
private final View mParent;
- private final UserGridView mUserGridView;
- private final UserSwitcherController mUserSwitcherController;
+ private final UserGridRecyclerView mUserGridView;
private final ProgressBar mSwitchingUsers;
private final int mShortAnimDuration;
private boolean mShowing;
- public FullscreenUserSwitcher(StatusBar statusBar,
- UserSwitcherController userSwitcherController,
- ViewStub containerStub) {
- mUserSwitcherController = userSwitcherController;
+ public FullscreenUserSwitcher(StatusBar statusBar, ViewStub containerStub, Context context) {
mParent = containerStub.inflate();
mContainer = mParent.findViewById(R.id.container);
mUserGridView = mContainer.findViewById(R.id.user_grid);
- mUserGridView.init(statusBar, mUserSwitcherController, true /* overrideAlpha */);
- mUserGridView.setUserSelectionListener(record -> {
- if (!record.isCurrent) {
- toggleSwitchInProgress(true);
- }
- });
+ mUserGridView.setStatusBar(statusBar);
+ GridLayoutManager layoutManager = new GridLayoutManager(context,
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ mUserGridView.setLayoutManager(layoutManager);
+ mUserGridView.buildAdapter();
+ mUserGridView.setUserSelectionListener(record -> toggleSwitchInProgress(true));
- PageIndicator pageIndicator = mContainer.findViewById(R.id.user_switcher_page_indicator);
- pageIndicator.setupWithViewPager(mUserGridView);
-
- Resources res = mContainer.getResources();
- mShortAnimDuration = res.getInteger(android.R.integer.config_shortAnimTime);
-
- mContainer.findViewById(R.id.start_driving).setOnClickListener(v -> {
- automaticallySelectUser();
- });
+ mShortAnimDuration = mContainer.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
mSwitchingUsers = mParent.findViewById(R.id.switching_users);
}
@@ -115,10 +105,4 @@ public class FullscreenUserSwitcher {
toggleSwitchInProgress(false);
mParent.setVisibility(View.GONE);
}
-
- private void automaticallySelectUser() {
- // TODO: Switch according to some policy. This implementation just tries to drop the
- // keyguard for the current user.
- mUserGridView.showOfflineAuthUi();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
new file mode 100644
index 000000000000..e09a36030cd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2018 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.car;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.GradientDrawable;
+import android.os.AsyncTask;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.settingslib.users.UserManagerHelper;
+import com.android.systemui.R;
+import com.android.systemui.qs.car.CarQSFragment;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Displays a GridLayout with icons for the users in the system to allow switching between users.
+ * One of the uses of this is for the lock screen in auto.
+ */
+public class UserGridRecyclerView extends RecyclerView implements
+ UserManagerHelper.OnUsersUpdateListener {
+
+ private StatusBar mStatusBar;
+ private UserSelectionListener mUserSelectionListener;
+ private UserAdapter mAdapter;
+ private UserManagerHelper mUserManagerHelper;
+ private Context mContext;
+
+ public UserGridRecyclerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ super.setHasFixedSize(true);
+ mContext = context;
+ mUserManagerHelper = new UserManagerHelper(mContext);
+ }
+
+ /**
+ * Register listener for any update to the users
+ */
+ @Override
+ public void onFinishInflate() {
+ mUserManagerHelper.registerOnUsersUpdateListener(this);
+ }
+
+ /**
+ * Unregisters listener checking for any change to the users
+ */
+ @Override
+ public void onDetachedFromWindow() {
+ mUserManagerHelper.unregisterOnUsersUpdateListener();
+ }
+
+ /**
+ * Initializes the adapter that populates the grid layout
+ *
+ * @return the adapter
+ */
+ public void buildAdapter() {
+ List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
+ .getAllUsers());
+ mAdapter = new UserAdapter(mContext, userRecords);
+ super.setAdapter(mAdapter);
+ }
+
+ public void setStatusBar(@Nullable StatusBar statusBar) {
+ mStatusBar = statusBar;
+ }
+
+ private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
+ List<UserRecord> userRecords = new ArrayList<>();
+ for (UserInfo userInfo : userInfoList) {
+ boolean isCurrent = false;
+ if (ActivityManager.getCurrentUser() == userInfo.id) {
+ isCurrent = true;
+ }
+ UserRecord record = new UserRecord(userInfo, false /* isGuest */,
+ false /* isAddUser */, isCurrent);
+ userRecords.add(record);
+ }
+
+ // Add guest user record if the current user is not a guest
+ if (!mUserManagerHelper.isGuestUser()) {
+ userRecords.add(addGuestUserRecord());
+ }
+
+ // Add add user record if the current user can add users
+ if (mUserManagerHelper.canAddUsers()) {
+ userRecords.add(addUserRecord());
+ }
+
+ return userRecords;
+ }
+
+ /**
+ * Create guest user record
+ */
+ private UserRecord addGuestUserRecord() {
+ UserInfo userInfo = new UserInfo();
+ userInfo.name = mContext.getString(R.string.car_guest);
+ return new UserRecord(userInfo, true /* isGuest */,
+ false /* isAddUser */, false /* isCurrent */);
+ }
+
+ /**
+ * Create add user record
+ */
+ private UserRecord addUserRecord() {
+ UserInfo userInfo = new UserInfo();
+ userInfo.name = mContext.getString(R.string.car_add_user);
+ return new UserRecord(userInfo, false /* isGuest */,
+ true /* isAddUser */, false /* isCurrent */);
+ }
+
+ public void onUserSwitched(int newUserId) {
+ // Bring up security view after user switch is completed.
+ post(this::showOfflineAuthUi);
+ }
+
+ public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
+ mUserSelectionListener = userSelectionListener;
+ }
+
+ void showOfflineAuthUi() {
+ // TODO: Show keyguard UI in-place.
+ if (mStatusBar != null) {
+ mStatusBar.executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ }
+ }
+
+ @Override
+ public void onUsersUpdate() {
+ mAdapter.clearUsers();
+ mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
+ mAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Adapter to populate the grid layout with the available user profiles
+ */
+ public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder> {
+
+ private final Context mContext;
+ private List<UserRecord> mUsers;
+ private final int mPodImageAvatarWidth;
+ private final int mPodImageAvatarHeight;
+ private final Resources mRes;
+ private final String mGuestName;
+ private final String mNewUserName;
+
+ public UserAdapter(Context context, List<UserRecord> users) {
+ mRes = context.getResources();
+ mContext = context;
+ updateUsers(users);
+ mPodImageAvatarWidth = mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_image_avatar_width);
+ mPodImageAvatarHeight = mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_image_avatar_height);
+ mGuestName = mRes.getString(R.string.car_guest);
+ mNewUserName = mRes.getString(R.string.car_new_user);
+ }
+
+ public void clearUsers() {
+ mUsers.clear();
+ }
+
+ public void updateUsers(List<UserRecord> users) {
+ mUsers = users;
+ }
+
+ @Override
+ public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.car_fullscreen_user_pod, parent, false);
+ view.setAlpha(1f);
+ view.bringToFront();
+ return new UserAdapterViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
+ UserRecord userRecord = mUsers.get(position);
+ holder.mUserAvatarImageView.setImageBitmap(getDefaultUserIcon(userRecord));
+ holder.mUserNameTextView.setText(userRecord.mInfo.name);
+ holder.mView.setOnClickListener(v -> {
+ if (userRecord == null) {
+ return;
+ }
+
+ // Notify the listener which user was selected
+ if (mUserSelectionListener != null) {
+ mUserSelectionListener.onUserSelected(userRecord);
+ }
+
+ // If the user selects Guest, switch to Guest profile
+ if (userRecord.mIsGuest) {
+ mUserManagerHelper.switchToGuest(mGuestName);
+ return;
+ }
+
+ // If the user wants to add a user, start task to add new user
+ if (userRecord.mIsAddUser) {
+ new AddNewUserTask().execute(mNewUserName);
+ return;
+ }
+
+ // If the user doesn't want to be a guest or add a user, switch to the user selected
+ mUserManagerHelper.switchToUser(userRecord.mInfo);
+ });
+
+ }
+
+ private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
+
+ @Override
+ protected UserInfo doInBackground(String... userNames) {
+ return mUserManagerHelper.createNewUser(userNames[0]);
+ }
+
+ @Override
+ protected void onPreExecute() {
+ }
+
+ @Override
+ protected void onPostExecute(UserInfo user) {
+ if (user != null) {
+ mUserManagerHelper.switchToUser(user);
+ }
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mUsers.size();
+ }
+
+ /**
+ * Returns the default user icon. This icon is a circle with a letter in it. The letter is
+ * the first character in the username.
+ *
+ * @param record the profile of the user for which the icon should be created
+ */
+ private Bitmap getDefaultUserIcon(UserRecord record) {
+ CharSequence displayText;
+ boolean isAddUserText = false;
+ if (record.mIsAddUser) {
+ displayText = "+";
+ isAddUserText = true;
+ } else {
+ displayText = record.mInfo.name.subSequence(0, 1);
+ }
+ Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(out);
+
+ // Draw the circle background.
+ GradientDrawable shape = new GradientDrawable();
+ shape.setShape(GradientDrawable.RADIAL_GRADIENT);
+ shape.setGradientRadius(1.0f);
+ shape.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_bgcolor));
+ shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
+ shape.draw(canvas);
+
+ // Draw the letter in the center.
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_fgcolor));
+ paint.setTextAlign(Align.CENTER);
+ if (isAddUserText) {
+ paint.setTextSize(mRes.getDimensionPixelSize(
+ R.dimen.car_touch_target_size));
+ } else {
+ paint.setTextSize(mRes.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_icon_text_size));
+ }
+
+ Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
+ // The Y coordinate is measured by taking half the height of the pod, but that would
+ // draw the character putting the bottom of the font in the middle of the pod. To
+ // correct this, half the difference between the top and bottom distance metrics of the
+ // font gives the offset of the font. Bottom is a positive value, top is negative, so
+ // the different is actually a sum. The "half" operation is then factored out.
+ canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
+ (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
+
+ return out;
+ }
+
+ public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
+
+ public ImageView mUserAvatarImageView;
+ public TextView mUserNameTextView;
+ public View mView;
+
+ public UserAdapterViewHolder(View view) {
+ super(view);
+ mView = view;
+ mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
+ mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
+ }
+ }
+ }
+
+ /**
+ * Object wrapper class for the userInfo. Use it to distinguish if a profile is a
+ * guest profile, add user profile, or a current user.
+ */
+ public static final class UserRecord {
+
+ public final UserInfo mInfo;
+ public final boolean mIsGuest;
+ public final boolean mIsAddUser;
+ public final boolean mIsCurrent;
+
+ public UserRecord(UserInfo userInfo, boolean isGuest, boolean isAddUser,
+ boolean isCurrent) {
+ mInfo = userInfo;
+ mIsGuest = isGuest;
+ mIsAddUser = isAddUser;
+ mIsCurrent = isCurrent;
+ }
+ }
+
+ /**
+ * Listener used to notify when a user has been selected
+ */
+ interface UserSelectionListener {
+
+ void onUserSelected(UserRecord record);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
deleted file mode 100644
index 1bd820db3f7c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * 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.car;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.qs.car.CarQSFragment;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Vector;
-
-/**
- * Displays a ViewPager with icons for the users in the system to allow switching between users.
- * One of the uses of this is for the lock screen in auto.
- */
-public class UserGridView extends ViewPager implements
- UserInfoController.OnUserInfoChangedListener {
- private StatusBar mStatusBar;
- private UserSwitcherController mUserSwitcherController;
- private Adapter mAdapter;
- private UserSelectionListener mUserSelectionListener;
- private UserInfoController mUserInfoController;
- private Vector mUserContainers;
- private int mContainerWidth;
- private boolean mOverrideAlpha;
- private CarQSFragment.UserSwitchCallback mUserSwitchCallback;
-
- public UserGridView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void init(StatusBar statusBar, UserSwitcherController userSwitcherController,
- boolean overrideAlpha) {
- mStatusBar = statusBar;
- mUserSwitcherController = userSwitcherController;
- mAdapter = new Adapter(mUserSwitcherController);
- mUserInfoController = Dependency.get(UserInfoController.class);
- mOverrideAlpha = overrideAlpha;
- // Whenever the container width changes, the containers must be refreshed. Instead of
- // doing an initial refreshContainers() to populate the containers, this listener will
- // refresh them on layout change because that affects how the users are split into
- // containers. Furthermore, at this point, the container width is unknown, so
- // refreshContainers() cannot populate any containers.
- addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- int newWidth = Math.max(left - right, right - left);
- if (mContainerWidth != newWidth) {
- mContainerWidth = newWidth;
- refreshContainers();
- }
- });
- }
-
- private void refreshContainers() {
- mUserContainers = new Vector();
-
- Context context = getContext();
- LayoutInflater inflater = LayoutInflater.from(context);
-
- for (int i = 0; i < mAdapter.getCount(); i++) {
- ViewGroup pods = (ViewGroup) inflater.inflate(
- R.layout.car_fullscreen_user_pod_container, null);
-
- int iconsPerPage = mAdapter.getIconsPerPage();
- int limit = Math.min(mUserSwitcherController.getUsers().size(), (i + 1) * iconsPerPage);
- for (int j = i * iconsPerPage; j < limit; j++) {
- View v = mAdapter.makeUserPod(inflater, context, j, pods);
- if (mOverrideAlpha) {
- v.setAlpha(1f);
- }
- pods.addView(v);
- // This is hacky, but the dividers on the pod container LinearLayout don't seem
- // to work for whatever reason. Instead, set a right margin on the pod if it's not
- // the right-most pod and there is more than one pod in the container.
- if (i < limit - 1 && limit > 1) {
- ViewGroup.MarginLayoutParams params =
- (ViewGroup.MarginLayoutParams) v.getLayoutParams();
- params.setMargins(0, 0, getResources().getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_margin_between), 0);
- v.setLayoutParams(params);
- }
- }
- mUserContainers.add(pods);
- }
-
- mAdapter = new Adapter(mUserSwitcherController);
- setAdapter(mAdapter);
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
- refreshContainers();
- }
-
- public void setUserSwitchCallback(CarQSFragment.UserSwitchCallback callback) {
- mUserSwitchCallback = callback;
- }
-
- public void onUserSwitched(int newUserId) {
- // Bring up security view after user switch is completed.
- post(this::showOfflineAuthUi);
- }
-
- public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
- mUserSelectionListener = userSelectionListener;
- }
-
- public void setListening(boolean listening) {
- if (listening) {
- mUserInfoController.addCallback(this);
- } else {
- mUserInfoController.removeCallback(this);
- }
- }
-
- void showOfflineAuthUi() {
- // TODO: Show keyguard UI in-place.
- mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true, true);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Wrap content doesn't work in ViewPagers, so simulate the behavior in code.
- int height = 0;
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
- height = MeasureSpec.getSize(heightMeasureSpec);
- } else {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- child.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- height = Math.max(child.getMeasuredHeight(), height);
- }
-
- // Respect the AT_MOST request from parent.
- if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
- height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height);
- }
- }
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
-
- /**
- * This is a ViewPager.PagerAdapter which deletegates the work to a
- * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have
- * to use composition instead to achieve the same goal since both the base classes are abstract
- * classes and not interfaces.
- */
- private final class Adapter extends PagerAdapter {
- private final int mPodWidth;
- private final int mPodMarginBetween;
- private final int mPodImageAvatarWidth;
- private final int mPodImageAvatarHeight;
-
- private final WrappedBaseUserAdapter mUserAdapter;
-
- public Adapter(UserSwitcherController controller) {
- super();
- mUserAdapter = new WrappedBaseUserAdapter(controller, this);
-
- Resources res = getResources();
- mPodWidth = res.getDimensionPixelSize(R.dimen.car_fullscreen_user_pod_width);
- mPodMarginBetween = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_margin_between);
- mPodImageAvatarWidth = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_width);
- mPodImageAvatarHeight = res.getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_image_avatar_height);
- }
-
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View) object);
- }
-
- private int getIconsPerPage() {
- // We need to know how many pods we need in this page. Each pod has its own width and
- // a margin between them. We can then divide the measured width of the parent by the
- // sum of pod width and margin to get the number of pods that will completely fit.
- // There is one less margin than the number of pods (eg. for 5 pods, there are 4
- // margins), so need to add the margin to the measured width to account for that.
- return (mContainerWidth + mPodMarginBetween) /
- (mPodWidth + mPodMarginBetween);
- }
-
- @Override
- public void finishUpdate(ViewGroup container) {
- if (mUserSwitchCallback != null) {
- mUserSwitchCallback.resetShowing();
- }
- }
-
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- if (position < mUserContainers.size()) {
- container.addView((View) mUserContainers.get(position));
- return mUserContainers.get(position);
- } else {
- return null;
- }
- }
-
- /**
- * Returns the default user icon. This icon is a circle with a letter in it. The letter is
- * the first character in the username.
- *
- * @param userName the username of the user for which the icon is to be created
- */
- private Bitmap getDefaultUserIcon(CharSequence userName) {
- CharSequence displayText = userName.subSequence(0, 1);
- Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(out);
-
- // Draw the circle background.
- GradientDrawable shape = new GradientDrawable();
- shape.setShape(GradientDrawable.RADIAL_GRADIENT);
- shape.setGradientRadius(1.0f);
- shape.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_bgcolor));
- shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
- shape.draw(canvas);
-
- // Draw the letter in the center.
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_fgcolor));
- paint.setTextAlign(Align.CENTER);
- paint.setTextSize(getResources().getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_icon_text_size));
- Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
- // The Y coordinate is measured by taking half the height of the pod, but that would
- // draw the character putting the bottom of the font in the middle of the pod. To
- // correct this, half the difference between the top and bottom distance metrics of the
- // font gives the offset of the font. Bottom is a positive value, top is negative, so
- // the different is actually a sum. The "half" operation is then factored out.
- canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
- (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
-
- return out;
- }
-
- private View makeUserPod(LayoutInflater inflater, Context context,
- int position, ViewGroup parent) {
- final UserSwitcherController.UserRecord record = mUserAdapter.getItem(position);
- View view = inflater.inflate(R.layout.car_fullscreen_user_pod, parent, false);
-
- TextView nameView = view.findViewById(R.id.user_name);
- if (record != null) {
- nameView.setText(mUserAdapter.getName(context, record));
- view.setActivated(record.isCurrent);
- } else {
- nameView.setText(context.getString(R.string.unknown_user_label));
- }
-
- ImageView iconView = (ImageView) view.findViewById(R.id.user_avatar);
- if (record == null || (record.picture == null && !record.isAddUser)) {
- iconView.setImageBitmap(getDefaultUserIcon(nameView.getText()));
- } else if (record.isAddUser) {
- Drawable icon = context.getDrawable(R.drawable.ic_add_circle_qs);
- icon.setTint(context.getColor(R.color.car_user_switcher_no_user_image_bgcolor));
- iconView.setImageDrawable(icon);
- } else {
- iconView.setImageBitmap(record.picture);
- }
-
- iconView.setOnClickListener(v -> {
- if (record == null) {
- return;
- }
-
- if (mUserSelectionListener != null) {
- mUserSelectionListener.onUserSelected(record);
- }
-
- if (record.isCurrent) {
- showOfflineAuthUi();
- } else {
- mUserSwitcherController.switchTo(record);
- }
- });
-
- return view;
- }
-
- @Override
- public int getCount() {
- int iconsPerPage = getIconsPerPage();
- if (iconsPerPage == 0) {
- return 0;
- }
- return (int) Math.ceil((double) mUserAdapter.getCount() / getIconsPerPage());
- }
-
- public void refresh() {
- mUserAdapter.refresh();
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
- }
- }
-
- private final class WrappedBaseUserAdapter extends UserSwitcherController.BaseUserAdapter {
- private final Adapter mContainer;
-
- public WrappedBaseUserAdapter(UserSwitcherController controller, Adapter container) {
- super(controller);
- mContainer = container;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- throw new UnsupportedOperationException("unused");
- }
-
- @Override
- public void notifyDataSetChanged() {
- super.notifyDataSetChanged();
- mContainer.notifyDataSetChanged();
- }
- }
-
- interface UserSelectionListener {
- void onUserSelected(UserSwitcherController.UserRecord record);
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 3bbfe3c1062c..b8bce95190f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -238,6 +238,7 @@ public class ActivityLaunchAnimator {
t.deferTransactionUntilSurface(app.leash, systemUiSurface,
systemUiSurface.getNextFrameNumber());
}
+ t.setEarlyWakeup();
t.apply();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index df2b817101ab..60a3474be684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -159,6 +159,11 @@ public class KeyguardBouncer {
*/
public void onFullyShown() {
mFalsingManager.onBouncerShown();
+ if (mKeyguardView == null) {
+ Log.wtf(TAG, "onFullyShown when view was null");
+ } else {
+ mKeyguardView.onResume();
+ }
}
/**
@@ -180,7 +185,6 @@ public class KeyguardBouncer {
@Override
public void run() {
mRoot.setVisibility(View.VISIBLE);
- mKeyguardView.onResume();
showPromptReason(mBouncerPromptReason);
final CharSequence customMessage = mCallback.consumeCustomMessage();
if (customMessage != null) {
@@ -296,7 +300,7 @@ public class KeyguardBouncer {
public boolean isShowing() {
return (mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE))
- && mExpansion == 0;
+ && mExpansion == 0 && !isAnimatingAway();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 3d7067d1d799..1fb1ddd5e70a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -99,6 +99,11 @@ public class KeyguardClockPositionAlgorithm {
private int mBurnInPreventionOffsetY;
/**
+ * Clock vertical padding when pulsing.
+ */
+ private int mPulsingPadding;
+
+ /**
* Doze/AOD transition amount.
*/
private float mDarkAmount;
@@ -109,9 +114,9 @@ public class KeyguardClockPositionAlgorithm {
private boolean mCurrentlySecure;
/**
- * If notification panel view currently has a touch.
+ * Dozing and receiving a notification (AOD notification.)
*/
- private boolean mTracking;
+ private boolean mPulsing;
/**
* Distance in pixels between the top of the screen and the first view of the bouncer.
@@ -130,11 +135,13 @@ public class KeyguardClockPositionAlgorithm {
R.dimen.burn_in_prevention_offset_x);
mBurnInPreventionOffsetY = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_y);
+ mPulsingPadding = res.getDimensionPixelSize(
+ R.dimen.widget_pulsing_bottom_padding);
}
public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
- float dark, boolean secure, boolean tracking, int bouncerTop) {
+ float dark, boolean secure, boolean pulsing, int bouncerTop) {
mMinTopMargin = minTopMargin + mContainerTopPadding;
mMaxShadeBottom = maxShadeBottom;
mNotificationStackHeight = notificationStackHeight;
@@ -144,7 +151,7 @@ public class KeyguardClockPositionAlgorithm {
mKeyguardStatusHeight = keyguardStatusHeight;
mDarkAmount = dark;
mCurrentlySecure = secure;
- mTracking = tracking;
+ mPulsing = pulsing;
mBouncerTop = bouncerTop;
}
@@ -152,7 +159,7 @@ public class KeyguardClockPositionAlgorithm {
final int y = getClockY();
result.clockY = y;
result.clockAlpha = getClockAlpha(y);
- result.stackScrollerPadding = y + mKeyguardStatusHeight;
+ result.stackScrollerPadding = y + (mPulsing ? 0 : mKeyguardStatusHeight);
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
}
@@ -194,9 +201,13 @@ public class KeyguardClockPositionAlgorithm {
private int getClockY() {
// Dark: Align the bottom edge of the clock at about half of the screen:
- final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
- final float clockYRegular = getExpandedClockPosition();
- final boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop;
+ float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
+ if (mPulsing) {
+ clockYDark -= mPulsingPadding;
+ }
+
+ float clockYRegular = getExpandedClockPosition();
+ boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop;
float clockYTarget = mCurrentlySecure && hasEnoughSpace ?
mMinTopMargin : -mKeyguardStatusHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
new file mode 100644
index 000000000000..759a0d173cdd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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.Nullable;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+
+
+/** Executes actions that require the screen to be unlocked. */
+public interface KeyguardDismissHandler {
+ /** Executes an action that requres the screen to be unlocked. */
+ void dismissKeyguardThenExecute(
+ OnDismissAction action, @Nullable Runnable cancelAction, boolean afterKeyguardGone);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
new file mode 100644
index 000000000000..c38b0b63190d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.util.Log;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+
+/**
+ * Executes actions that require the screen to be unlocked. Delegates the actual handling to an
+ * implementation passed via {@link #setDismissHandler}.
+ */
+public class KeyguardDismissUtil implements KeyguardDismissHandler {
+ private static final String TAG = "KeyguardDismissUtil";
+
+ private volatile KeyguardDismissHandler mDismissHandler;
+
+ /** Sets the actual {@link DismissHandler} implementation. */
+ public void setDismissHandler(KeyguardDismissHandler dismissHandler) {
+ mDismissHandler = dismissHandler;
+ }
+
+ /**
+ * Executes an action that requres the screen to be unlocked.
+ *
+ * <p>Must be called after {@link #setDismissHandler}.
+ */
+ @Override
+ public void dismissKeyguardThenExecute(
+ OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) {
+ KeyguardDismissHandler dismissHandler = mDismissHandler;
+ if (dismissHandler == null) {
+ Log.wtf(TAG, "KeyguardDismissHandler not set.");
+ action.onDismiss();
+ return;
+ }
+ dismissHandler.dismissKeyguardThenExecute(action, cancelAction, afterKeyguardGone);
+ }
+}
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 4c4eb60e4412..db2139da6b76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,7 +39,6 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
-import android.os.VibrationEffect;
import android.support.annotation.ColorInt;
import android.util.AttributeSet;
import android.util.Log;
@@ -69,7 +68,6 @@ import com.android.systemui.recents.RecentsOnboarding;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
@@ -150,7 +148,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private Divider mDivider;
private RecentsOnboarding mRecentsOnboarding;
private NotificationPanelView mPanelView;
- private final VibratorHelper mVibratorHelper;
private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
@@ -246,7 +243,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
- mVibratorHelper = Dependency.get(VibratorHelper.class);
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -314,9 +310,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
} else if (mRecentsButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_OVERVIEW;
}
-
- // Vibrate tick whenever down occurs on navigation bar
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
break;
}
return mGestureHelper.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index b6a11f71f251..6bc19ea69be7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -125,7 +125,14 @@ public class NotificationIconAreaController implements DarkReceiver {
} else {
mTintArea.set(tintArea);
}
- mIconTint = iconTint;
+ if (mNotificationIconArea != null) {
+ if (DarkIconDispatcher.isInArea(tintArea, mNotificationIconArea)) {
+ mIconTint = iconTint;
+ }
+ } else {
+ mIconTint = iconTint;
+ }
+
applyNotificationIconsTint();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 55174349cc53..8c257fe255a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -151,6 +151,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private ArrayMap<String, ArrayList<StatusBarIcon>> mReplacingIcons;
// Keep track of the last visible icon so collapsed container can report on its location
private IconState mLastVisibleIconState;
+ private IconState mFirstVisibleIconState;
private float mVisualOverflowStart;
// Keep track of overflow in range [0, 3]
private int mNumDots;
@@ -159,7 +160,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private int[] mAbsolutePosition = new int[2];
private View mIsolatedIconForAnimation;
-
public NotificationIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
initDimens();
@@ -192,10 +192,15 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
paint.setColor(Color.BLUE);
canvas.drawLine(end, 0, end, height, paint);
- paint.setColor(Color.BLACK);
+ paint.setColor(Color.GREEN);
int lastIcon = (int) mLastVisibleIconState.xTranslation;
canvas.drawLine(lastIcon, 0, lastIcon, height, paint);
+ if (mFirstVisibleIconState != null) {
+ int firstIcon = (int) mFirstVisibleIconState.xTranslation;
+ canvas.drawLine(firstIcon, 0, firstIcon, height, paint);
+ }
+
paint.setColor(Color.RED);
canvas.drawLine(mVisualOverflowStart, 0, mVisualOverflowStart, height, paint);
@@ -210,6 +215,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
super.onConfigurationChanged(newConfig);
initDimens();
}
+
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
float centerY = getHeight() / 2.0f;
@@ -364,11 +370,15 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
float layoutEnd = getLayoutEnd();
float overflowStart = getMaxOverflowStart();
mVisualOverflowStart = 0;
+ mFirstVisibleIconState = null;
boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
IconState iconState = mIconStates.get(view);
iconState.xTranslation = translationX;
+ if (mFirstVisibleIconState == null) {
+ mFirstVisibleIconState = iconState;
+ }
boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
&& iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
boolean noOverflowAfter = i == childCount - 1;
@@ -417,10 +427,16 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
} else if (childCount > 0) {
View lastChild = getChildAt(childCount - 1);
mLastVisibleIconState = mIconStates.get(lastChild);
+ mFirstVisibleIconState = mIconStates.get(getChildAt(0));
}
boolean center = mDark;
if (center && translationX < getLayoutEnd()) {
- float delta = (getLayoutEnd() - translationX) / 2;
+ float initialTranslation =
+ mFirstVisibleIconState == null ? 0 : mFirstVisibleIconState.xTranslation;
+ float contentWidth = getFinalTranslationX() - initialTranslation;
+ float availableSpace = getLayoutEnd() - getActualPaddingStart();
+ float delta = (availableSpace - contentWidth) / 2;
+
if (firstOverflowIndex != -1) {
// If we have an overflow, only count those half for centering because the dots
// don't have a lot of visual weight.
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 27ca0d11ee28..351633b590c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -238,6 +238,7 @@ public class NotificationPanelView extends PanelView implements
private boolean mIsFullWidth;
private float mDarkAmount;
private float mDarkAmountTarget;
+ private boolean mPulsing;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private boolean mNoVisibleNotifications = true;
private ValueAnimator mDarkAnimator;
@@ -477,7 +478,7 @@ public class NotificationPanelView extends PanelView implements
mKeyguardStatusView.getHeight(),
mDarkAmount,
mStatusBar.isKeyguardCurrentlySecure(),
- mTracking,
+ mPulsing,
mBouncerTop);
mClockPositionAlgorithm.run(mClockPositionResult);
if (animate || mClockAnimator != null) {
@@ -659,6 +660,14 @@ public class NotificationPanelView extends PanelView implements
expand(true /* animate */);
}
+ public void expandWithoutQs() {
+ if (isQsExpanded()) {
+ flingSettings(0 /* velocity */, false /* expand */);
+ } else {
+ expand(true /* animate */);
+ }
+ }
+
@Override
public void fling(float vel, boolean expand) {
GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
@@ -2681,14 +2690,8 @@ public class NotificationPanelView extends PanelView implements
positionClockAndNotifications();
}
- public void setNoVisibleNotifications(boolean noNotifications) {
- mNoVisibleNotifications = noNotifications;
- if (mQs != null) {
- mQs.setHasNotifications(!noNotifications);
- }
- }
-
public void setPulsing(boolean pulsing) {
+ mPulsing = pulsing;
mKeyguardStatusView.setPulsing(pulsing);
positionClockAndNotifications();
mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1]
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 28f31621d2d1..cc143bb848cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -68,8 +68,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private static final String TAG = "ScrimController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ /**
+ * General scrim animation duration.
+ */
public static final long ANIMATION_DURATION = 220;
-
+ /**
+ * Longer duration, currently only used when going to AOD.
+ */
+ public static final long ANIMATION_DURATION_LONG = 1000;
/**
* When both scrims have 0 alpha.
*/
@@ -85,7 +91,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
/**
* Default alpha value for most scrims.
*/
- public static final float GRADIENT_SCRIM_ALPHA = 0.45f;
+ public static final float GRADIENT_SCRIM_ALPHA = 0.70f;
/**
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
@@ -105,7 +111,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private final Context mContext;
protected final ScrimView mScrimBehind;
protected final ScrimView mScrimInFront;
- private final LightBarController mLightBarController;
private final UnlockMethodCache mUnlockMethodCache;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DozeParameters mDozeParameters;
@@ -139,6 +144,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private int mCurrentBehindTint;
private boolean mWallpaperVisibilityTimedOut;
private int mScrimsVisibility;
+ private final Consumer<GradientColors> mScrimInFrontColorListener;
+ private final Consumer<Float> mScrimBehindAlphaListener;
private final Consumer<Integer> mScrimVisibleListener;
private boolean mBlankScreen;
private boolean mScreenBlankingCallbackCalled;
@@ -155,17 +162,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private boolean mWakeLockHeld;
private boolean mKeyguardOccluded;
- public ScrimController(LightBarController lightBarController, ScrimView scrimBehind,
- ScrimView scrimInFront, Consumer<Integer> scrimVisibleListener,
- DozeParameters dozeParameters, AlarmManager alarmManager) {
+ public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
+ Consumer<Float> scrimBehindAlphaListener,
+ Consumer<GradientColors> scrimInFrontColorListener,
+ Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
+ AlarmManager alarmManager) {
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
+ mScrimBehindAlphaListener = scrimBehindAlphaListener;
+ mScrimInFrontColorListener = scrimInFrontColorListener;
mScrimVisibleListener = scrimVisibleListener;
mContext = scrimBehind.getContext();
mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- mLightBarController = lightBarController;
mScrimBehindAlphaResValue = mContext.getResources().getFloat(R.dimen.scrim_behind_alpha);
mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout,
"hide_aod_wallpaper", new Handler());
@@ -190,6 +200,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
}
mState = ScrimState.UNINITIALIZED;
+ mScrimBehind.setDefaultFocusHighlightEnabled(false);
+ mScrimInFront.setDefaultFocusHighlightEnabled(false);
+
updateScrims();
}
@@ -361,6 +374,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
setOrAdaptCurrentAnimation(mScrimBehind);
setOrAdaptCurrentAnimation(mScrimInFront);
+
+ mScrimBehindAlphaListener.accept(mScrimBehind.getViewAlpha());
}
}
@@ -389,7 +404,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
// Darken scrim as you pull down the shade when unlocked
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
- mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
+ mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
mCurrentInFrontAlpha = 0;
} else if (mState == ScrimState.KEYGUARD) {
// Either darken of make the scrim transparent when you
@@ -469,7 +484,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
4.5f /* minimumContrast */) / 255f;
mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
- mLightBarController.setScrimColor(mScrimInFront.getColors());
+ mScrimInFrontColorListener.accept(mScrimInFront.getColors());
}
// We want to override the back scrim opacity for the AOD state
@@ -528,8 +543,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
if (alpha == 0f) {
scrim.setClickable(false);
} else {
- // Eat touch events (unless dozing).
- scrim.setClickable(!mState.isLowPowerState());
+ // Eat touch events (unless dozing or pulsing).
+ scrim.setClickable(mState != ScrimState.AOD && mState != ScrimState.PULSING);
}
updateScrim(scrim, alpha);
}
@@ -696,9 +711,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
}
}
- // TODO factor mLightBarController out of this class
if (scrim == mScrimBehind) {
- mLightBarController.setScrimAlpha(alpha);
+ mScrimBehindAlphaListener.accept(alpha);
}
final boolean wantsAlphaUpdate = alpha != currentAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index f4b6c38c4f6e..bbdaa9993bec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -111,9 +111,10 @@ public enum ScrimState {
mCurrentInFrontAlpha = alwaysOnEnabled ? mAodFrontScrimAlpha : 1f;
mCurrentInFrontTint = Color.BLACK;
mCurrentBehindTint = Color.BLACK;
- // DisplayPowerManager will blank the screen for us, we just need
- // to set our state.
- mAnimateChange = !mDisplayRequiresBlanking;
+ mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
+ // DisplayPowerManager may blank the screen for us,
+ // in this case we just need to set our state.
+ mAnimateChange = mDozeParameters.shouldControlScreenOff();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index f7a97be3b0f2..4b2bc45bf417 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -213,6 +213,7 @@ import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -915,8 +916,14 @@ public class StatusBar extends SystemUI implements DemoMode,
ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
- mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
+ mScrimController = SystemUIFactory.getInstance().createScrimController(
scrimBehind, scrimInFront, mLockscreenWallpaper,
+ scrimBehindAlpha -> {
+ mLightBarController.setScrimAlpha(scrimBehindAlpha);
+ },
+ scrimInFrontColor -> {
+ mLightBarController.setScrimColor(scrimInFrontColor);
+ },
scrimsVisible -> {
if (mStatusBarWindowManager != null) {
mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
@@ -1300,6 +1307,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightBarController.setFingerprintUnlockController(mFingerprintUnlockController);
+ Dependency.get(KeyguardDismissUtil.class).setDismissHandler(
+ this::dismissKeyguardThenExecute);
Trace.endSection();
}
@@ -1425,13 +1434,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void addQsTile(ComponentName tile) {
- if (mQSPanel.getHost() != null) {
+ if (mQSPanel != null && mQSPanel.getHost() != null) {
mQSPanel.getHost().addTile(tile);
}
}
public void remQsTile(ComponentName tile) {
- if (mQSPanel.getHost() != null) {
+ if (mQSPanel != null && mQSPanel.getHost() != null) {
mQSPanel.getHost().removeTile(tile);
}
}
@@ -1443,7 +1452,8 @@ public class StatusBar extends SystemUI implements DemoMode,
@VisibleForTesting
protected void updateFooter() {
boolean showFooterView = mState != StatusBarState.KEYGUARD
- && mEntryManager.getNotificationData().getActiveNotifications().size() != 0;
+ && mEntryManager.getNotificationData().getActiveNotifications().size() != 0
+ && !mRemoteInputManager.getController().isRemoteInputActive();
boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
&& hasActiveClearableNotifications();
@@ -2047,11 +2057,19 @@ public class StatusBar extends SystemUI implements DemoMode,
}
/**
+ * Decides if the status bar (clock + notifications + signal cluster) should be visible
+ * or not when showing the bouncer.
+ *
+ * We want to hide it when:
+ * • User swipes up on the keyguard
+ * • Locked activity that doesn't show a status bar requests the bouncer
+ *
* @param animate should the change of the icons be animated.
*/
private void updateHideIconsForBouncer(boolean animate) {
- boolean shouldHideIconsForBouncer = !mPanelExpanded && mTopHidesStatusBar && mIsOccluded
- && (mBouncerShowing || mStatusBarWindowHidden);
+ boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded;
+ boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
+ boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
mHideIconsForBouncer = shouldHideIconsForBouncer;
if (!shouldHideIconsForBouncer && mBouncerWasShowingWhenHidden) {
@@ -2290,7 +2308,7 @@ public class StatusBar extends SystemUI implements DemoMode,
return ;
}
- mNotificationPanel.expand(true /* animate */);
+ mNotificationPanel.expandWithoutQs();
if (false) postStartTracing();
}
@@ -2815,6 +2833,7 @@ public class StatusBar extends SystemUI implements DemoMode,
boolean remoteInputActive) {
mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
entry.row.notifyHeightChanged(true /* needsAnimation */);
+ updateFooter();
}
public void lockScrollTo(NotificationData.Entry entry) {
mStackScroller.lockScrollTo(entry.row);
@@ -3888,7 +3907,11 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public boolean onBackPressed() {
- if (mStatusBarKeyguardViewManager.onBackPressed()) {
+ boolean isScrimmedBouncer = mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
+ if (mStatusBarKeyguardViewManager.onBackPressed(isScrimmedBouncer /* hideImmediately */)) {
+ if (!isScrimmedBouncer) {
+ mNotificationPanel.expandWithoutQs();
+ }
return true;
}
if (mNotificationPanel.isQsExpanded()) {
@@ -3919,7 +3942,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
private void showBouncerIfKeyguard() {
- if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+ if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
+ && !mKeyguardViewMediator.isHiding()) {
showBouncer(true /* animated */);
}
}
@@ -4983,6 +5007,14 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onNotificationClicked(StatusBarNotification sbn, ExpandableNotificationRow row) {
+ RemoteInputController controller = mRemoteInputManager.getController();
+ if (controller.isRemoteInputActive(row.getEntry())
+ && !TextUtils.isEmpty(row.getActiveRemoteInputText())) {
+ // We have an active remote input typed and the user clicked on the notification.
+ // this was probably unintentional, so we're closing the edit text instead.
+ controller.closeRemoteInputs();
+ return;
+ }
Notification notification = sbn.getNotification();
final PendingIntent intent = notification.contentIntent != null
? notification.contentIntent
@@ -5046,12 +5078,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Intent fillInIntent = null;
Entry entry = row.getEntry();
CharSequence remoteInputText = null;
- RemoteInputController controller = mRemoteInputManager.getController();
- if (controller.isRemoteInputActive(entry)) {
- remoteInputText = row.getActiveRemoteInputText();
- }
- if (TextUtils.isEmpty(remoteInputText)
- && !TextUtils.isEmpty(entry.remoteInputText)) {
+ if (!TextUtils.isEmpty(entry.remoteInputText)) {
remoteInputText = entry.remoteInputText;
}
if (!TextUtils.isEmpty(remoteInputText)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 510af03e6f28..b4e7575d1480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -306,17 +306,6 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
}
- /**
- * For mobile essentially (an array of holders in one slot)
- */
- private void handleSet(int slotIndex, List<StatusBarIconHolder> holders) {
- for (StatusBarIconHolder holder : holders) {
- int viewIndex = getViewIndex(slotIndex, holder.getTag());
- mIconLogger.onIconVisibility(getSlotName(slotIndex), holder.isVisible());
- mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
- }
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG + " state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 6b6ea10bfa63..670c68f3eb22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -89,7 +89,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected boolean mFirstUpdate = true;
protected boolean mLastShowing;
protected boolean mLastOccluded;
- private boolean mLastTracking;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
@@ -152,28 +151,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// • The user quickly taps on the display and we show "swipe up to unlock."
// • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
// • Full-screen user switcher is displayed.
- final boolean noLongerTracking = mLastTracking != tracking && !tracking;
if (mOccluded || mNotificationPanelView.isUnlockHintRunning()
|| mBouncer.willDismissWithAction()
|| mStatusBar.isFullScreenUserSwitcherState()) {
mBouncer.setExpansion(0);
} else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
mBouncer.setExpansion(expansion);
- if (expansion == 1) {
- mBouncer.onFullyHidden();
- } else if (!mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
+ if (expansion != 1 && tracking && !mBouncer.isShowing()
+ && !mBouncer.isAnimatingAway()) {
mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
- } else if (noLongerTracking) {
- // Notify that falsing manager should stop its session when user stops touching,
- // even before the animation ends, to guarantee that we're not recording sensitive
- // data.
- mBouncer.onFullyShown();
- }
- if (expansion == 0 || expansion == 1) {
+ } else if (expansion == 0 || expansion == 1) {
updateStates();
}
}
- mLastTracking = tracking;
}
/**
@@ -522,12 +512,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
/**
* Notifies this manager that the back button has been pressed.
*
+ * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
+ * Non-scrimmed bouncers have a special animation tied to the expansion
+ * of the notification panel.
* @return whether the back press has been handled
*/
- public boolean onBackPressed() {
+ public boolean onBackPressed(boolean hideImmediately) {
if (mBouncer.isShowing()) {
mStatusBar.endAffordanceLaunch();
- reset(true /* hideBouncerWhenShowing */);
+ reset(hideImmediately);
return true;
}
return false;
@@ -595,6 +588,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
mStatusBar.setBouncerShowing(bouncerShowing);
+ if (bouncerShowing) {
+ mBouncer.onFullyShown();
+ } else {
+ mBouncer.onFullyHidden();
+ }
}
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 1d9f01dd7adc..127fdfe8a931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -415,7 +415,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
@Override public String toString() {
return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
- + roaming + ", visible=" + visible + ")";
+ + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 4c92d01eae4c..9aa804484716 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.policy;
-import libcore.icu.LocaleData;
-
-import android.app.ActivityManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -40,11 +37,13 @@ import android.view.Display;
import android.view.View;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -52,6 +51,8 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import libcore.icu.LocaleData;
+
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
@@ -65,6 +66,9 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
public static final String CLOCK_SECONDS = "clock_seconds";
+ private final CurrentUserTracker mCurrentUserTracker;
+ private int mCurrentUserId;
+
private boolean mClockVisibleByPolicy = true;
private boolean mClockVisibleByUser = true;
@@ -84,6 +88,17 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
private boolean mShowSeconds;
private Handler mSecondsHandler;
+ /**
+ * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings
+ * for text.
+ */
+ private boolean mUseWallpaperTextColor;
+
+ /**
+ * Color to be set on this {@link TextView}, when wallpaperTextColor is <b>not</b> utilized.
+ */
+ private int mNonAdaptedColor;
+
public Clock(Context context) {
this(context, null);
}
@@ -101,9 +116,16 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
try {
mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
mShowDark = a.getBoolean(R.styleable.Clock_showDark, true);
+ mNonAdaptedColor = getCurrentTextColor();
} finally {
a.recycle();
}
+ mCurrentUserTracker = new CurrentUserTracker(context) {
+ @Override
+ public void onUserSwitched(int newUserId) {
+ mCurrentUserId = newUserId;
+ }
+ };
}
@Override
@@ -128,6 +150,8 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
}
+ mCurrentUserTracker.startTracking();
+ mCurrentUserId = mCurrentUserTracker.getCurrentUserId();
}
// NOTE: It's safe to do these after registering the receiver since the receiver always runs
@@ -153,6 +177,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
}
+ mCurrentUserTracker.stopTracking();
}
}
@@ -227,7 +252,10 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ mNonAdaptedColor = DarkIconDispatcher.getTint(area, this, tint);
+ if (!mUseWallpaperTextColor) {
+ setTextColor(mNonAdaptedColor);
+ }
}
@Override
@@ -242,6 +270,25 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
0);
}
+ /**
+ * Sets whether the clock uses the wallpaperTextColor. If we're not using it, we'll revert back
+ * to dark-mode-based/tinted colors.
+ *
+ * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color
+ */
+ public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
+ if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) {
+ return;
+ }
+ mUseWallpaperTextColor = shouldUseWallpaperTextColor;
+
+ if (mUseWallpaperTextColor) {
+ setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor));
+ } else {
+ setTextColor(mNonAdaptedColor);
+ }
+ }
+
private void updateShowSeconds() {
if (mShowSeconds) {
// Wait until we have a display to start trying to show seconds.
@@ -267,7 +314,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
private final CharSequence getSmallTime() {
Context context = getContext();
- boolean is24 = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser());
+ boolean is24 = DateFormat.is24HourFormat(context, mCurrentUserId);
LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
final char MAGIC1 = '\uEF00';
@@ -357,8 +404,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
} else if (hhmm != null && hhmm.length() == 4) {
int hh = Integer.parseInt(hhmm.substring(0, 2));
int mm = Integer.parseInt(hhmm.substring(2));
- boolean is24 = DateFormat.is24HourFormat(
- getContext(), ActivityManager.getCurrentUser());
+ boolean is24 = DateFormat.is24HourFormat(getContext(), mCurrentUserId);
if (is24) {
mCalendar.set(Calendar.HOUR_OF_DAY, hh);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 74a30fa8094f..ef630c7205e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -27,6 +27,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -42,6 +43,17 @@ public class DateView extends TextView {
private String mLastText;
private String mDatePattern;
+ /**
+ * Whether we should use colors that adapt based on wallpaper/the scrim behind quick settings
+ * for text.
+ */
+ private boolean mUseWallpaperTextColor;
+
+ /**
+ * Color to be set on this {@link TextView}, when wallpaperTextColor is <b>not</b> utilized.
+ */
+ private int mNonAdaptedTextColor;
+
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -62,6 +74,7 @@ public class DateView extends TextView {
public DateView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mNonAdaptedTextColor = getCurrentTextColor();
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.DateView,
@@ -117,6 +130,25 @@ public class DateView extends TextView {
}
}
+ /**
+ * Sets whether the date view uses the wallpaperTextColor. If we're not using it, we'll revert
+ * back to dark-mode-based/tinted colors.
+ *
+ * @param shouldUseWallpaperTextColor whether we should use wallpaperTextColor for text color
+ */
+ public void useWallpaperTextColor(boolean shouldUseWallpaperTextColor) {
+ if (shouldUseWallpaperTextColor == mUseWallpaperTextColor) {
+ return;
+ }
+ mUseWallpaperTextColor = shouldUseWallpaperTextColor;
+
+ if (mUseWallpaperTextColor) {
+ setTextColor(Utils.getColorAttr(mContext, R.attr.wallpaperTextColor));
+ } else {
+ setTextColor(mNonAdaptedTextColor);
+ }
+ }
+
public void setDatePattern(String pattern) {
if (TextUtils.equals(pattern, mDatePattern)) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 2fed3fca24e5..1b02e152ec11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -28,7 +28,6 @@ import android.metrics.LogMaker;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
-import android.os.VibrationEffect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
@@ -50,7 +49,6 @@ import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.VibratorHelper;
import static android.view.KeyEvent.KEYCODE_HOME;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
@@ -75,7 +73,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private OnClickListener mOnClickListener;
private final KeyButtonRipple mRipple;
private final OverviewProxyService mOverviewProxyService;
- private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final Runnable mCheckLongPress = new Runnable() {
@@ -121,7 +118,6 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mRipple = new KeyButtonRipple(context, this);
- mVibratorHelper = Dependency.get(VibratorHelper.class);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
setBackground(mRipple);
}
@@ -262,9 +258,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
if (showSwipeUI) {
if (doIt) {
- if (doHapticFeedback) {
- mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
- }
+ // Apply haptic feedback on touch up since there is none on touch down
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
playSoundEffect(SoundEffectConstants.CLICK);
}
} else if (doHapticFeedback && !mLongClicked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 790135fc03ca..74b39268fc2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -20,8 +20,10 @@ import android.view.ViewGroup;
import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.text.BreakIterator;
import java.util.Comparator;
@@ -42,6 +44,7 @@ public class SmartReplyView extends ViewGroup {
private static final int SQUEEZE_FAILED = -1;
private final SmartReplyConstants mConstants;
+ private final KeyguardDismissUtil mKeyguardDismissUtil;
/** Spacing to be applied between views. */
private final int mSpacing;
@@ -62,6 +65,7 @@ public class SmartReplyView extends ViewGroup {
public SmartReplyView(Context context, AttributeSet attrs) {
super(context, attrs);
mConstants = Dependency.get(SmartReplyConstants.class);
+ mKeyguardDismissUtil = Dependency.get(KeyguardDismissUtil.class);
int spacing = 0;
int singleLineButtonPaddingHorizontal = 0;
@@ -126,12 +130,13 @@ public class SmartReplyView extends ViewGroup {
}
@VisibleForTesting
- static Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice,
+ Button inflateReplyButton(Context context, ViewGroup root, CharSequence choice,
RemoteInput remoteInput, PendingIntent pendingIntent) {
Button b = (Button) LayoutInflater.from(context).inflate(
R.layout.smart_reply_button, root, false);
b.setText(choice);
- b.setOnClickListener(view -> {
+
+ OnDismissAction action = () -> {
Bundle results = new Bundle();
results.putString(remoteInput.getResultKey(), choice.toString());
Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -142,6 +147,12 @@ public class SmartReplyView extends ViewGroup {
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Unable to send smart reply", e);
}
+ return false; // do not defer
+ };
+
+ b.setOnClickListener(view -> {
+ mKeyguardDismissUtil.dismissKeyguardThenExecute(
+ action, null /* cancelAction */, false /* afterKeyguardGone */);
});
return b;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 7c1c566a57bf..91a4b07c2109 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -70,8 +70,8 @@ public class AmbientState {
private int mIntrinsicPadding;
private int mExpandAnimationTopChange;
private ExpandableNotificationRow mExpandingNotification;
- private boolean mFullyDark;
private int mDarkTopPadding;
+ private float mDarkAmount;
public AmbientState(Context context) {
reload(context);
@@ -149,6 +149,16 @@ public class AmbientState {
mDark = dark;
}
+ /** Dark ratio of the status bar **/
+ public void setDarkAmount(float darkAmount) {
+ mDarkAmount = darkAmount;
+ }
+
+ /** Returns the dark ratio of the status bar */
+ public float getDarkAmount() {
+ return mDarkAmount;
+ }
+
public void setHideSensitive(boolean hideSensitive) {
mHideSensitive = hideSensitive;
}
@@ -413,17 +423,10 @@ public class AmbientState {
}
/**
- * {@see isFullyDark}
- */
- public void setFullyDark(boolean fullyDark) {
- mFullyDark = fullyDark;
- }
-
- /**
* @return {@code true } when shade is completely dark: in AOD or ambient display.
*/
public boolean isFullyDark() {
- return mFullyDark;
+ return mDarkAmount == 1;
}
public void setDarkTopPadding(int darkTopPadding) {
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 375e8606258f..bc5a848f9f2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -96,6 +96,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -269,8 +270,6 @@ public class NotificationStackScrollLayout extends ViewGroup
*/
private boolean mOnlyScrollingInThisMotion;
private boolean mDisallowDismissInThisMotion;
- private boolean mInterceptDelegateEnabled;
- private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
private long mGoToFullShadeDelay;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -562,17 +561,17 @@ public class NotificationStackScrollLayout extends ViewGroup
return;
}
- final int color;
- if (mAmbientState.isDark()) {
- color = Color.WHITE;
- } else {
- float alpha =
- BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
- alpha *= 1f - mDarkAmount;
- // We need to manually blend in the background color
- int scrimColor = mScrimController.getBackgroundColor();
- color = ColorUtils.blendARGB(scrimColor, mBgColor, alpha);
- }
+ float alpha =
+ BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
+ alpha *= 1f - mDarkAmount;
+ // We need to manually blend in the background color.
+ int scrimColor = mScrimController.getBackgroundColor();
+ int awakeColor = ColorUtils.blendARGB(scrimColor, mBgColor, alpha);
+
+ // Interpolate between semi-transparent notification panel background color
+ // and white AOD separator.
+ float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(mDarkAmount);
+ int color = ColorUtils.blendARGB(awakeColor, Color.WHITE, colorInterpolation);
if (mCachedBackgroundColor != color) {
mCachedBackgroundColor = color;
@@ -3023,6 +3022,11 @@ public class NotificationStackScrollLayout extends ViewGroup
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
updateNotificationAnimationStates();
+ if (!animationsEnabled) {
+ mSwipedOutViews.clear();
+ mChildrenToRemoveAnimated.clear();
+ clearTemporaryViewsInGroup(this);
+ }
}
private void updateNotificationAnimationStates() {
@@ -3090,6 +3094,21 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public void changeViewPosition(View child, int newIndex) {
int currentIndex = indexOfChild(child);
+
+ if (currentIndex == -1) {
+ boolean isTransient = false;
+ if (child instanceof ExpandableNotificationRow
+ && ((ExpandableNotificationRow)child).getTransientContainer() != null) {
+ isTransient = true;
+ }
+ Log.e(TAG, "Attempting to re-position "
+ + (isTransient ? "transient" : "")
+ + " view {"
+ + child
+ + "}");
+ return;
+ }
+
if (child != null && child.getParent() == this && currentIndex != newIndex) {
mChangePositionInProgress = true;
((ExpandableView)child).setChangingPosition(true);
@@ -3569,17 +3588,17 @@ public class NotificationStackScrollLayout extends ViewGroup
private void clearTemporaryViews() {
// lets make sure nothing is in the overlay / transient anymore
- clearTemporaryViews(this);
+ clearTemporaryViewsInGroup(this);
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- clearTemporaryViews(row.getChildrenContainer());
+ clearTemporaryViewsInGroup(row.getChildrenContainer());
}
}
}
- private void clearTemporaryViews(ViewGroup viewGroup) {
+ private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
viewGroup.removeTransientView(viewGroup.getTransientView(0));
}
@@ -3922,12 +3941,11 @@ public class NotificationStackScrollLayout extends ViewGroup
requestChildrenUpdate();
applyCurrentBackgroundBounds();
updateWillNotDraw();
- updateAntiBurnInTranslation();
notifyHeightChangeListener(mShelf);
}
private void updateAntiBurnInTranslation() {
- setTranslationX(mAmbientState.isDark() ? mAntiBurnInOffsetX : 0);
+ setTranslationX(mAntiBurnInOffsetX * mDarkAmount);
}
/**
@@ -3942,12 +3960,18 @@ public class NotificationStackScrollLayout extends ViewGroup
private void setDarkAmount(float darkAmount) {
mDarkAmount = darkAmount;
- final boolean fullyDark = darkAmount == 1;
- if (mAmbientState.isFullyDark() != fullyDark) {
- mAmbientState.setFullyDark(fullyDark);
+ boolean wasFullyDark = mAmbientState.isFullyDark();
+ mAmbientState.setDarkAmount(darkAmount);
+ if (mAmbientState.isFullyDark() != wasFullyDark) {
updateContentHeight();
+ DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
+ if (mAmbientState.isFullyDark() && dozeParameters.shouldControlScreenOff()) {
+ mShelf.fadeInTranslating();
+ }
}
updateBackgroundDimming();
+ updateAntiBurnInTranslation();
+ requestChildrenUpdate();
}
public float getDarkAmount() {
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 a8d2d98b6f2b..f4d7f8d48a66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -276,8 +276,6 @@ public class StackScrollAlgorithm {
if (i >= firstHiddenIndex) {
// we need normal padding now, to be in sync with what the stack calculates
lastView = null;
- ExpandableViewState viewState = resultState.getViewStateForView(v);
- viewState.hidden = true;
}
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
float increasedPadding = v.getIncreasedPaddingAmount();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 5a4478f072e0..639e49b1a17f 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -58,7 +58,7 @@ public class TunerServiceImpl extends TunerService {
private static final String TUNER_VERSION = "sysui_tuner_version";
- private static final int CURRENT_TUNER_VERSION = 2;
+ private static final int CURRENT_TUNER_VERSION = 3;
private final Observer mObserver = new Observer();
// Map of Uris we listen on to their settings keys.
@@ -119,6 +119,10 @@ public class TunerServiceImpl extends TunerService {
if (oldVersion < 2) {
setTunerEnabled(mContext, false);
}
+ if (oldVersion < 3) {
+ // Delay this so that we can wait for everything to be registered first.
+ new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(() -> clearAll(), 5000);
+ }
setValue(TUNER_VERSION, newVersion);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index e18140984f0e..a901e88219a5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,7 +23,7 @@ import android.os.Handler;
*/
public class DelayedWakeLock implements WakeLock {
- private static final long RELEASE_DELAY_MS = 240;
+ private static final long RELEASE_DELAY_MS = 140;
private final Handler mHandler;
private final WakeLock mInner;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 13157fe19c30..9036a8ad620e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -212,7 +212,6 @@ public class VolumeDialogImpl implements VolumeDialog {
.setDuration(300)
.setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
.withEndAction(() -> {
- mWindow.getDecorView().requestAccessibilityFocus();
if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
mRingerIcon.postOnAnimationDelayed(mSinglePress, 1500);
}
@@ -302,15 +301,8 @@ public class VolumeDialogImpl implements VolumeDialog {
if (D.BUG) Slog.d(TAG, "Adding row for stream " + stream);
VolumeRow row = new VolumeRow();
initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
- if (dynamic && mRows.size() > 2) {
- // Dynamic Streams should be the first in the list, so they're shown to start of
- // everything except a11y
- mDialogRowsView.addView(row.view, 1);
- mRows.add(1, row);
- } else {
- mDialogRowsView.addView(row.view);
- mRows.add(row);
- }
+ mDialogRowsView.addView(row.view);
+ mRows.add(row);
}
private void addExistingRows() {
@@ -604,7 +596,8 @@ public class VolumeDialogImpl implements VolumeDialog {
return activeRow.stream == STREAM_RING
|| activeRow.stream == STREAM_ALARM
|| activeRow.stream == STREAM_VOICE_CALL
- || activeRow.stream == STREAM_ACCESSIBILITY;
+ || activeRow.stream == STREAM_ACCESSIBILITY
+ || mDynamic.get(activeRow.stream);
}
return false;