diff options
Diffstat (limited to 'packages/SystemUI/src')
45 files changed, 1092 insertions, 392 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java index 9c206e2..d406f5b 100644 --- a/packages/SystemUI/src/com/android/systemui/DemoMode.java +++ b/packages/SystemUI/src/com/android/systemui/DemoMode.java @@ -24,6 +24,8 @@ public interface DemoMode { public static final String ACTION_DEMO = "com.android.systemui.demo"; + public static final String EXTRA_COMMAND = "command"; + public static final String COMMAND_ENTER = "enter"; public static final String COMMAND_EXIT = "exit"; public static final String COMMAND_CLOCK = "clock"; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index e302c98..33bd726 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -40,13 +40,14 @@ public class SystemUIApplication extends Application { * The classes of the stuff to start. */ private final Class<?>[] SERVICES = new Class[] { + com.android.systemui.tuner.TunerService.class, com.android.systemui.keyguard.KeyguardViewMediator.class, com.android.systemui.recents.Recents.class, com.android.systemui.volume.VolumeUI.class, com.android.systemui.statusbar.SystemBars.class, com.android.systemui.usb.StorageNotification.class, com.android.systemui.power.PowerUI.class, - com.android.systemui.media.RingtonePlayer.class + com.android.systemui.media.RingtonePlayer.class, }; /** diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 08659e9..3e122da 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -9,17 +9,19 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.database.ContentObserver; import android.graphics.PixelFormat; import android.media.AudioAttributes; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; -import android.os.Vibrator; import android.provider.Settings; import android.util.Log; import android.view.Gravity; +import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -55,6 +57,8 @@ public class AssistManager { private final PhoneStatusBar mBar; private final IVoiceInteractionManagerService mVoiceInteractionManagerService; + private ComponentName mAssistComponent; + private IVoiceInteractionSessionShowCallback mShowCallback = new IVoiceInteractionSessionShowCallback.Stub() { @@ -77,12 +81,24 @@ public class AssistManager { } }; + private final ContentObserver mAssistSettingsObserver = new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + updateAssistInfo(); + } + }; + public AssistManager(PhoneStatusBar bar, Context context) { mContext = context; mBar = bar; mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface( ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); + + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), false, + mAssistSettingsObserver); + mAssistSettingsObserver.onChange(false); } public void onConfigurationChanged() { @@ -107,22 +123,31 @@ public class AssistManager { } public void onGestureInvoked(boolean vibrate) { - boolean isVoiceInteractorActive = getVoiceInteractorSupportsAssistGesture(); - if (!isVoiceInteractorActive && !isAssistantIntentAvailable()) { + if (mAssistComponent == null) { return; } + if (vibrate) { vibrate(); } - if (!isVoiceInteractorActive || !isVoiceSessionRunning()) { + final boolean isService = isAssistantService(); + if (isService || !isVoiceSessionRunning()) { showOrb(); - mView.postDelayed(mHideRunnable, isVoiceInteractorActive + mView.postDelayed(mHideRunnable, isService ? TIMEOUT_SERVICE : TIMEOUT_ACTIVITY); } startAssist(); } + public void hideAssist() { + try { + mVoiceInteractionManagerService.hideCurrentSession(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call hideCurrentSession", e); + } + } + private WindowManager.LayoutParams getLayoutParams() { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -148,10 +173,12 @@ public class AssistManager { } private void startAssist() { - if (getVoiceInteractorSupportsAssistGesture()) { - startVoiceInteractor(); - } else { - startAssistActivity(); + if (mAssistComponent != null) { + if (isAssistantService()) { + startVoiceInteractor(); + } else { + startAssistActivity(); + } } } @@ -169,6 +196,9 @@ public class AssistManager { if (intent == null) { return; } + if (mAssistComponent != null) { + intent.setComponent(mAssistComponent); + } try { final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, @@ -246,19 +276,9 @@ public class AssistManager { } private void maybeSwapSearchIcon() { - Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); - ComponentName component = null; - boolean isService = false; - if (getVoiceInteractorSupportsAssistGesture()) { - component = getVoiceInteractorComponentName(); - isService = true; - } else if (intent != null) { - component = intent.getComponent(); - } - if (component != null) { - replaceDrawable(mView.getOrb().getLogo(), component, ASSIST_ICON_METADATA_NAME, - isService); + if (mAssistComponent != null) { + replaceDrawable(mView.getOrb().getLogo(), mAssistComponent, ASSIST_ICON_METADATA_NAME, + isAssistantService()); } else { mView.getOrb().getLogo().setImageDrawable(null); } @@ -296,17 +316,35 @@ public class AssistManager { } private void vibrate() { - if (Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0) { - Resources res = mContext.getResources(); - Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); - vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration), - VIBRATION_ATTRIBUTES); - } + mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); } - public boolean isAssistantIntentAvailable() { - return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; + private boolean isAssistantService() { + return mAssistComponent == null ? + false : mAssistComponent.equals(getVoiceInteractorComponentName()); + } + + private void updateAssistInfo() { + final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.ASSISTANT, UserHandle.USER_CURRENT); + if (setting != null) { + mAssistComponent = ComponentName.unflattenFromString(setting); + return; + } + + // Fallback to keep backward compatible behavior when there is no user setting. + if (getVoiceInteractorSupportsAssistGesture()) { + mAssistComponent = getVoiceInteractorComponentName(); + return; + } + + Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) + .getAssistIntent(mContext, false, UserHandle.USER_CURRENT); + if (intent != null) { + mAssistComponent = intent.getComponent(); + return; + } + + mAssistComponent = null; } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 1f3a830..3f72125 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -82,11 +82,9 @@ public class DozeLog { sNotificationPulseStats.append(); } - public static void traceDozing(Context context, boolean dozing) { - if (!ENABLED) return; - sPulsing = false; + private static void init(Context context) { synchronized (DozeLog.class) { - if (dozing && sMessages == null) { + if (sMessages == null) { sTimes = new long[SIZE]; sMessages = new String[SIZE]; sSince = System.currentTimeMillis(); @@ -105,6 +103,12 @@ public class DozeLog { KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback); } } + } + + public static void traceDozing(Context context, boolean dozing) { + if (!ENABLED) return; + sPulsing = false; + init(context); log("dozing " + dozing); } @@ -146,10 +150,12 @@ public class DozeLog { } } - public static void traceProximityResult(boolean near, long millis, int pulseReason) { + public static void traceProximityResult(Context context, boolean near, long millis, + int pulseReason) { if (!ENABLED) return; log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near + " millis=" + millis); + init(context); sProxStats[pulseReason][near ? 0 : 1].append(); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 8d27450..5d46712 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -235,7 +235,7 @@ public class DozeService extends DreamService { public void onProximityResult(int result) { final boolean isNear = result == RESULT_NEAR; final long end = SystemClock.uptimeMillis(); - DozeLog.traceProximityResult(isNear, end - start, reason); + DozeLog.traceProximityResult(mContext, isNear, end - start, reason); if (nonBlocking) { // we already continued return; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 0dcc0b9..f00fed5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -455,7 +455,7 @@ public class KeyguardViewMediator extends SystemUI { @Override public void onFingerprintAuthenticated(int userId) { if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - mViewMediatorCallback.keyguardDone(true); + mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(); } else { mStatusBarKeyguardViewManager.animateCollapsePanels( FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); @@ -658,7 +658,7 @@ public class KeyguardViewMediator extends SystemUI { mPendingLock = true; } - if (mPendingLock || mPendingReset) { + if (mPendingLock) { playSounds(true); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index 88d0997..2a84362 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -96,6 +96,7 @@ public class MediaProjectionPermissionActivity extends Activity .create(); mDialog.create(); + mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); ((CheckBox) mDialog.findViewById(R.id.remember)).setOnCheckedChangeListener(this); mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index cd4f299..25e3d10 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -111,6 +111,8 @@ public class QSPanel extends ViewGroup { mDetailDoneButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + announceForAccessibility( + mContext.getString(R.string.accessibility_desc_quick_settings)); closeDetail(); } }); @@ -392,6 +394,9 @@ public class QSPanel extends ViewGroup { mDetail.bringToFront(); mDetailContent.addView(r.detailView); MetricsLogger.visible(mContext, detailAdapter.getMetricsCategory()); + announceForAccessibility(mContext.getString( + R.string.accessibility_quick_settings_detail, + mContext.getString(detailAdapter.getTitle()))); setDetailRecord(r); listener = mHideGridContentWhenDone; if (r instanceof TileRecord) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index c06ea66..937615a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -92,7 +92,7 @@ public class CastTile extends QSTile<QSTile.BooleanState> { @Override protected void handleUpdateState(BooleanState state, Object arg) { - state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing()); + state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing() && !mKeyguard.isTrusted()); state.label = mContext.getString(R.string.quick_settings_cast_title); state.value = false; state.autoMirrorDrawable = false; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 0369ab5..5d74604 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -74,7 +74,11 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements state.visible = mFlashlightController.isAvailable(); state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); if (arg instanceof UserBoolean) { - state.value = ((UserBoolean) arg).value; + boolean value = ((UserBoolean) arg).value; + if (value == state.value) { + return; + } + state.value = value; } final AnimationIcon icon = state.value ? mEnable : mDisable; icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index bbd3e60..442af90 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -32,6 +32,7 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; +import android.os.AsyncTask; import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; @@ -40,6 +41,7 @@ import android.util.Pair; import android.view.Display; import android.view.LayoutInflater; import android.view.View; + import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SystemUI; @@ -184,12 +186,16 @@ public class Recents extends SystemUI // Header (for transition) TaskViewHeader mHeaderBar; + final Object mHeaderBarLock = new Object(); TaskStackView mDummyStackView; // Variables to keep track of if we need to start recents after binding boolean mTriggeredFromAltTab; long mLastToggleTime; + Bitmap mThumbnailTransitionBitmapCache; + Task mThumbnailTransitionBitmapCacheKey; + public Recents() { } @@ -359,14 +365,19 @@ public class Recents extends SystemUI void preloadRecentsInternal() { // Preload only the raw task list into a new load plan (which will be consumed by the - // RecentsActivity) + // RecentsActivity) only if there is a task to animate to. + ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask(); + MutableBoolean topTaskHome = new MutableBoolean(true); RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); sInstanceLoadPlan = loader.createLoadPlan(mContext); - - ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask(); - MutableBoolean isTopTaskHome = new MutableBoolean(true); - if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) { - sInstanceLoadPlan.preloadRawTasks(isTopTaskHome.value); + if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) { + sInstanceLoadPlan.preloadRawTasks(topTaskHome.value); + loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value); + TaskStack top = sInstanceLoadPlan.getAllTaskStacks().get(0); + if (top.getTaskCount() > 0) { + preCacheThumbnailTransitionBitmapAsync(topTask, top, mDummyStackView, + topTaskHome.value); + } } } @@ -513,12 +524,14 @@ public class Recents extends SystemUI algo.computeRects(mWindowRect.width(), mWindowRect.height(), taskStackBounds); Rect taskViewSize = algo.getUntransformedTaskViewSize(); int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); - mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, - false); - mHeaderBar.measure( - View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY)); - mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); + synchronized (mHeaderBarLock) { + mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, + false); + mHeaderBar.measure( + View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY)); + mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); + } } /** Prepares the search bar app widget */ @@ -607,30 +620,27 @@ public class Recents extends SystemUI */ ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) { + // Update the destination rect Task toTask = new Task(); TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, topTask.id, toTask); - if (toTransform != null && toTask.key != null) { - Rect toTaskRect = toTransform.rect; - int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale); - int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); - Bitmap thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, - Bitmap.Config.ARGB_8888); - if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { - thumbnail.eraseColor(0xFFff0000); - } else { - Canvas c = new Canvas(thumbnail); - c.scale(toTransform.scale, toTransform.scale); - mHeaderBar.rebindToTask(toTask); - mHeaderBar.draw(c); - c.setBitmap(null); - } - Bitmap thumbnailImmutable = thumbnail.createAshmemBitmap(); - + Rect toTaskRect = toTransform.rect; + Bitmap thumbnail; + if (mThumbnailTransitionBitmapCacheKey != null + && mThumbnailTransitionBitmapCacheKey.key != null + && mThumbnailTransitionBitmapCacheKey.key.equals(toTask.key)) { + thumbnail = mThumbnailTransitionBitmapCache; + mThumbnailTransitionBitmapCacheKey = null; + mThumbnailTransitionBitmapCache = null; + } else { + preloadIcon(topTask); + thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform); + } + if (thumbnail != null) { mStartAnimationTriggered = false; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView, - thumbnailImmutable, toTaskRect.left, toTaskRect.top, toTaskRect.width(), + thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), toTaskRect.height(), mHandler, this); } @@ -638,6 +648,72 @@ public class Recents extends SystemUI return getUnknownTransitionActivityOptions(); } + /** + * Preloads the icon of a task. + */ + void preloadIcon(ActivityManager.RunningTaskInfo task) { + + // Ensure that we load the running task's icon + RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); + launchOpts.runningTaskId = task.id; + launchOpts.loadThumbnails = false; + launchOpts.onlyLoadForCache = true; + RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts); + } + + /** + * Caches the header thumbnail used for a window animation asynchronously into + * {@link #mThumbnailTransitionBitmapCache}. + */ + void preCacheThumbnailTransitionBitmapAsync(ActivityManager.RunningTaskInfo topTask, + TaskStack stack, TaskStackView stackView, boolean isTopTaskHome) { + preloadIcon(topTask); + + // Update the destination rect + mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, isTopTaskHome); + final Task toTask = new Task(); + final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, + topTask.id, toTask); + new AsyncTask<Void, Void, Bitmap>() { + @Override + protected Bitmap doInBackground(Void... params) { + return drawThumbnailTransitionBitmap(toTask, toTransform); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + mThumbnailTransitionBitmapCache = bitmap; + mThumbnailTransitionBitmapCacheKey = toTask; + } + }.execute(); + } + + /** + * Draws the header of a task used for the window animation into a bitmap. + */ + Bitmap drawThumbnailTransitionBitmap(Task toTask, TaskViewTransform toTransform) { + if (toTransform != null && toTask.key != null) { + Bitmap thumbnail; + synchronized (mHeaderBarLock) { + int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale); + int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); + thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, + Bitmap.Config.ARGB_8888); + if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { + thumbnail.eraseColor(0xFFff0000); + } else { + Canvas c = new Canvas(thumbnail); + c.scale(toTransform.scale, toTransform.scale); + mHeaderBar.rebindToTask(toTask); + mHeaderBar.draw(c); + c.setBitmap(null); + } + } + return thumbnail.createAshmemBitmap(); + } + return null; + } + /** Returns the transition rect for the given task id. */ TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, TaskStackView stackView, int runningTaskId, Task runningTaskOut) { @@ -694,7 +770,9 @@ public class Recents extends SystemUI return; } - loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); + if (!sInstanceLoadPlan.hasTasks()) { + loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); + } ArrayList<TaskStack> stacks = sInstanceLoadPlan.getAllTaskStacks(); TaskStack stack = stacks.get(0); @@ -706,12 +784,6 @@ public class Recents extends SystemUI boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks; if (useThumbnailTransition) { - // Ensure that we load the running task's icon - RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); - launchOpts.runningTaskId = topTask.id; - launchOpts.loadThumbnails = false; - launchOpts.onlyLoadForCache = true; - loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts); // Try starting with a thumbnail transition ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index ad97f91..3885799 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -81,6 +81,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Runnables to finish the Recents activity FinishRecentsRunnable mFinishLaunchHomeRunnable; + // Runnable to be executed after we paused ourselves + Runnable mAfterPauseRunnable; + /** * A common Runnable to finish Recents either by calling finish() (with a custom animation) or * launching Home with some ActivityOptions. Generally we always launch home when we exit @@ -441,6 +444,19 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (mConfig.launchedHasConfigurationChanged) { onEnterAnimationTriggered(); } + + if (!mConfig.launchedHasConfigurationChanged) { + mRecentsView.disableLayersForOneFrame(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mAfterPauseRunnable != null) { + mRecentsView.post(mAfterPauseRunnable); + mAfterPauseRunnable = null; + } } @Override @@ -624,6 +640,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Recents.startScreenPinning(this, ssp); } + @Override + public void runAfterPause(Runnable r) { + mAfterPauseRunnable = r; + } + /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/ @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java index 4b5c0bd..3f5d0a8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeImageView.java @@ -73,4 +73,9 @@ public class FixedSizeImageView extends ImageView { mAllowRelayout = true; mAllowInvalidate = true; } + + @Override + public boolean hasOverlappingRendering() { + return false; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index cec613c..fa97a86 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -24,14 +24,19 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; import android.net.Uri; +import android.os.Bundle; +import android.os.IRemoteCallback; +import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.util.AttributeSet; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewStub; import android.view.WindowInsets; +import android.view.WindowManagerGlobal; import android.widget.FrameLayout; + import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsAppWidgetHostView; @@ -52,6 +57,8 @@ import java.util.List; public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks, RecentsPackageMonitor.PackageCallbacks { + private static final String TAG = "RecentsView"; + /** The RecentsView callbacks */ public interface RecentsViewCallbacks { public void onTaskViewClicked(); @@ -59,8 +66,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV public void onAllTaskViewsDismissed(); public void onExitToHomeAnimationTriggered(); public void onScreenPinningRequest(); - public void onTaskResize(Task t); + public void runAfterPause(Runnable r); } RecentsConfiguration mConfig; @@ -431,11 +438,75 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV return false; } + public void disableLayersForOneFrame() { + List<TaskStackView> stackViews = getTaskStackViews(); + for (int i = 0; i < stackViews.size(); i++) { + stackViews.get(i).disableLayersForOneFrame(); + } + } + + private void postDrawHeaderThumbnailTransitionRunnable(final TaskView tv, final int offsetX, + final int offsetY, final TaskViewTransform transform, + final ActivityOptions.OnAnimationStartedListener animStartedListener) { + Runnable r = new Runnable() { + @Override + public void run() { + // Disable any focused state before we draw the header + if (tv.isFocusedTask()) { + tv.unsetFocusedTask(); + } + + float scale = tv.getScaleX(); + int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale); + int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale); + + Bitmap b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight, + Bitmap.Config.ARGB_8888); + if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { + b.eraseColor(0xFFff0000); + } else { + Canvas c = new Canvas(b); + c.scale(tv.getScaleX(), tv.getScaleY()); + tv.mHeaderView.draw(c); + c.setBitmap(null); + } + b = b.createAshmemBitmap(); + int[] pts = new int[2]; + tv.getLocationOnScreen(pts); + try { + WindowManagerGlobal.getWindowManagerService() + .overridePendingAppTransitionAspectScaledThumb(b, + pts[0] + offsetX, + pts[1] + offsetY, + transform.rect.width(), + transform.rect.height(), + new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) + throws RemoteException { + post(new Runnable() { + @Override + public void run() { + if (animStartedListener != null) { + animStartedListener.onAnimationStarted(); + } + } + }); + } + }, true); + } catch (RemoteException e) { + Log.w(TAG, "Error overriding app transition", e); + } + } + }; + mCb.runAfterPause(r); + } /**** TaskStackView.TaskStackCallbacks Implementation ****/ @Override public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv, final TaskStack stack, final Task task, final boolean lockToTask) { + // Notify any callbacks of the launching of a new task if (mCb != null) { mCb.onTaskViewClicked(); @@ -466,31 +537,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV ActivityOptions opts = null; if (task.thumbnail != null && task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) { - Bitmap b; - if (tv != null) { - // Disable any focused state before we draw the header - if (tv.isFocusedTask()) { - tv.unsetFocusedTask(); - } - - float scale = tv.getScaleX(); - int fromHeaderWidth = (int) (tv.mHeaderView.getMeasuredWidth() * scale); - int fromHeaderHeight = (int) (tv.mHeaderView.getMeasuredHeight() * scale); - b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight, - Bitmap.Config.ARGB_8888); - if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { - b.eraseColor(0xFFff0000); - } else { - Canvas c = new Canvas(b); - c.scale(tv.getScaleX(), tv.getScaleY()); - tv.mHeaderView.draw(c); - c.setBitmap(null); - } - } else { - // Notify the system to skip the thumbnail layer by using an ALPHA_8 bitmap - b = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); - } - Bitmap bImmut = b.createAshmemBitmap(); ActivityOptions.OnAnimationStartedListener animStartedListener = null; if (lockToTask) { animStartedListener = new ActivityOptions.OnAnimationStartedListener() { @@ -509,6 +555,10 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } }; } + if (tv != null) { + postDrawHeaderThumbnailTransitionRunnable(tv, offsetX, offsetY, transform, + animStartedListener); + } if (mConfig.multiStackEnabled) { opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(), R.anim.recents_from_unknown_enter, @@ -516,7 +566,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV sourceView.getHandler(), animStartedListener); } else { opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView, - bImmut, offsetX, offsetY, transform.rect.width(), transform.rect.height(), + Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(), + offsetX, offsetY, transform.rect.width(), transform.rect.height(), sourceView.getHandler(), animStartedListener); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 5f151e8..5711cd6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -19,6 +19,7 @@ package com.android.systemui.recents.views; import android.animation.ValueAnimator; import android.content.ComponentName; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; import android.view.LayoutInflater; @@ -63,7 +64,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void onTaskResize(Task t); } - RecentsConfiguration mConfig; TaskStack mStack; @@ -81,7 +81,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal boolean mDismissAllButtonAnimating; int mFocusedTaskIndex = -1; int mPrevAccessibilityFocusedIndex = -1; - // Optimizations int mStackViewsAnimationDuration; boolean mStackViewsDirty = true; @@ -99,6 +98,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>(); List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>(); LayoutInflater mInflater; + boolean mLayersDisabled; // A convenience update listener to request updating clipping of tasks ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener = @@ -375,7 +375,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (tv == null) { tv = mViewPool.pickUpViewFromPool(task, task); - + if (mLayersDisabled) { + tv.disableLayersForOneFrame(); + } if (mStackViewsAnimationDuration > 0) { // For items in the list, put them in start animating them from the // approriate ends of the list where they are expected to appear @@ -1031,6 +1033,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mUIDozeTrigger.poke(); } + @Override + protected void dispatchDraw(Canvas canvas) { + mLayersDisabled = false; + super.dispatchDraw(canvas); + } + + public void disableLayersForOneFrame() { + mLayersDisabled = true; + List<TaskView> taskViews = getTaskViews(); + for (int i = 0; i < taskViews.size(); i++) { + taskViews.get(i).disableLayersForOneFrame(); + } + } + /**** TaskStackCallbacks Implementation ****/ @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 01ed08a..5906ef1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -22,6 +22,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.*; import android.util.AttributeSet; +import android.view.accessibility.AccessibilityManager; import android.view.View; import android.view.ViewOutlineProvider; import android.view.animation.AccelerateInterpolator; @@ -366,7 +367,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, .setStartDelay(delay) .setDuration(duration) .setInterpolator(PhoneStatusBar.ALPHA_IN) - .withLayer() .start(); } @@ -415,7 +415,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, .setStartDelay(0) .setDuration(mConfig.taskViewExitToAppDuration) .setInterpolator(mConfig.fastOutLinearInInterpolator) - .withLayer() .start(); } else { // Hide the dismiss button @@ -650,6 +649,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } + public void disableLayersForOneFrame() { + mHeaderView.disableLayersForOneFrame(); + } + /**** TaskCallbacks Implementation ****/ /** Binds this task view to the task */ @@ -672,7 +675,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mThumbnailView.rebindToTask(mTask); mHeaderView.rebindToTask(mTask); // Rebind any listeners - mHeaderView.mApplicationIcon.setOnClickListener(this); + AccessibilityManager am = (AccessibilityManager) getContext(). + getSystemService(Context.ACCESSIBILITY_SERVICE); + if (Constants.DebugFlags.App.EnableTaskFiltering || (am != null && am.isEnabled())) { + mHeaderView.mApplicationIcon.setOnClickListener(this); + } mHeaderView.mDismissButton.setOnClickListener(this); if (mConfig.multiStackEnabled) { mHeaderView.mMoveTaskButton.setOnClickListener(this); @@ -718,9 +725,19 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, postDelayed(new Runnable() { @Override public void run() { - if (Constants.DebugFlags.App.EnableTaskFiltering && v == mHeaderView.mApplicationIcon) { - if (mCb != null) { - mCb.onTaskViewAppIconClicked(tv); + if (v == mHeaderView.mApplicationIcon) { + if (Constants.DebugFlags.App.EnableTaskFiltering) { + if (mCb != null) { + mCb.onTaskViewAppIconClicked(tv); + } + } else { + AccessibilityManager am = (AccessibilityManager) getContext(). + getSystemService(Context.ACCESSIBILITY_SERVICE); + if (am != null && am.isEnabled()) { + if (mCb != null) { + mCb.onTaskViewAppInfoClicked(tv); + } + } } } else if (v == mHeaderView.mDismissButton) { dismissTask(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index f397bc3..6db4020 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; @@ -80,6 +81,8 @@ public class TaskViewHeader extends FrameLayout { Paint mDimLayerPaint = new Paint(); PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); + boolean mLayersDisabled; + public TaskViewHeader(Context context) { this(context, null); } @@ -172,7 +175,9 @@ public class TaskViewHeader extends FrameLayout { void setDimAlpha(int alpha) { mDimColorFilter.setColor(Color.argb(alpha, 0, 0, 0)); mDimLayerPaint.setColorFilter(mDimColorFilter); - setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); + if (!mLayersDisabled) { + setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); + } } /** Returns the secondary color for a primary color. */ @@ -190,14 +195,14 @@ public class TaskViewHeader extends FrameLayout { } else if (t.applicationIcon != null) { mApplicationIcon.setImageDrawable(t.applicationIcon); } - mApplicationIcon.setContentDescription(t.contentDescription); if (!mActivityDescription.getText().toString().equals(t.activityLabel)) { mActivityDescription.setText(t.activityLabel); } mActivityDescription.setContentDescription(t.contentDescription); // Try and apply the system ui tint - int existingBgColor = getBackgroundColor(); + int existingBgColor = (getBackground() instanceof ColorDrawable) ? + ((ColorDrawable) getBackground()).getColor() : 0; if (existingBgColor != t.colorPrimary) { mBackgroundColorDrawable.setColor(t.colorPrimary); mBackgroundColor = t.colorPrimary; @@ -263,7 +268,6 @@ public class TaskViewHeader extends FrameLayout { .setStartDelay(0) .setInterpolator(mConfig.fastOutSlowInInterpolator) .setDuration(mConfig.taskViewExitToAppDuration) - .withLayer() .start(); } } @@ -278,7 +282,6 @@ public class TaskViewHeader extends FrameLayout { .setStartDelay(0) .setInterpolator(mConfig.fastOutLinearInInterpolator) .setDuration(mConfig.taskViewEnterFromAppDuration) - .withLayer() .start(); } } @@ -305,6 +308,28 @@ public class TaskViewHeader extends FrameLayout { return new int[] {}; } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (mLayersDisabled) { + mLayersDisabled = false; + postOnAnimation(new Runnable() { + @Override + public void run() { + mLayersDisabled = false; + setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); + } + }); + } + } + + public void disableLayersForOneFrame() { + mLayersDisabled = true; + + // Disable layer for a frame so we can draw our first frame faster. + setLayerType(LAYER_TYPE_NONE, null); + } + /** Notifies the associated TaskView has been focused. */ void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) { // If we are not animating the visible state, just return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index fa172a4..c945fc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -92,6 +92,7 @@ import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SwipeHelper; import com.android.systemui.SystemUI; +import com.android.systemui.assist.AssistManager; import com.android.systemui.recents.Recents; import com.android.systemui.statusbar.NotificationData.Entry; import com.android.systemui.statusbar.phone.NavigationBarView; @@ -240,6 +241,8 @@ public abstract class BaseStatusBar extends SystemUI implements private NotificationClicker mNotificationClicker = new NotificationClicker(); + protected AssistManager mAssistManager; + @Override // NotificationData.Environment public boolean isDeviceProvisioned() { return mDeviceProvisioned; @@ -1030,9 +1033,7 @@ public abstract class BaseStatusBar extends SystemUI implements @Override public void toggleRecentApps() { - int msg = MSG_TOGGLE_RECENTS_APPS; - mHandler.removeMessages(msg); - mHandler.sendEmptyMessage(msg); + toggleRecents(); } @Override @@ -1628,6 +1629,7 @@ public abstract class BaseStatusBar extends SystemUI implements // TODO: Dismiss Keyguard. } if (intent.isActivity()) { + mAssistManager.hideAssist(); overrideActivityPendingAppTransition(keyguardShowing && !afterKeyguardGone); } @@ -1646,7 +1648,7 @@ public abstract class BaseStatusBar extends SystemUI implements true /* force */, true /* delayed */); visibilityChanged(false); - return intent != null && intent.isActivity(); + return true; } }, afterKeyguardGone); } @@ -1904,7 +1906,7 @@ public abstract class BaseStatusBar extends SystemUI implements logUpdate(entry, n); } boolean applyInPlace = shouldApplyInPlace(entry, n); - boolean shouldInterrupt = shouldInterrupt(notification); + boolean shouldInterrupt = shouldInterrupt(entry); boolean alertAgain = alertAgain(entry, n); entry.notification = notification; @@ -2075,7 +2077,8 @@ public abstract class BaseStatusBar extends SystemUI implements || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; } - protected boolean shouldInterrupt(StatusBarNotification sbn) { + protected boolean shouldInterrupt(Entry entry) { + StatusBarNotification sbn = entry.notification; if (mNotificationData.shouldFilterOut(sbn)) { if (DEBUG) { Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out."); @@ -2100,10 +2103,12 @@ public abstract class BaseStatusBar extends SystemUI implements Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER; boolean accessibilityForcesLaunch = isFullscreen && mAccessibilityManager.isTouchExplorationEnabled(); + boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent(); boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker))) && isAllowed && !accessibilityForcesLaunch + && !justLaunchedFullScreenIntent && mPowerManager.isScreenOn() && (!mStatusBarKeyguardViewManager.isShowing() || mStatusBarKeyguardViewManager.isOccluded()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java index 00665f4..a323684 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissViewButton.java @@ -48,15 +48,14 @@ public class DismissViewButton extends Button { public DismissViewButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mAnimatedDismissDrawable = (AnimatedVectorDrawable) getContext().getResources().getDrawable( + mAnimatedDismissDrawable = (AnimatedVectorDrawable) getContext().getDrawable( R.drawable.dismiss_all_shape_animation).mutate(); mAnimatedDismissDrawable.setCallback(this); mAnimatedDismissDrawable.setBounds(0, 0, mAnimatedDismissDrawable.getIntrinsicWidth(), mAnimatedDismissDrawable.getIntrinsicHeight()); - mStaticDismissDrawable = getContext().getResources().getDrawable( - R.drawable.dismiss_all_shape); + mStaticDismissDrawable = getContext().getDrawable(R.drawable.dismiss_all_shape); mStaticDismissDrawable.setBounds(0, 0, mStaticDismissDrawable.getIntrinsicWidth(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 9ef495d..d444ea8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -903,12 +903,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { return mShowingPublic ? mPublicLayout : mPrivateLayout; } + @Override + public void setShowingLegacyBackground(boolean showing) { + super.setShowingLegacyBackground(showing); + mPrivateLayout.setShowingLegacyBackground(showing); + mPublicLayout.setShowingLegacyBackground(showing); + } + public void setExpansionLogger(ExpansionLogger logger, String key) { mLogger = logger; mLoggingKey = key; } - private void logExpansionEvent(boolean userAction, boolean wasExpanded) { final boolean nowExpanded = isExpanded(); if (wasExpanded != nowExpanded && mLogger != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 374d970..58fb2b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -60,22 +60,18 @@ public class KeyguardAffordanceView extends ImageView { private final int mNormalColor; private final ArgbEvaluator mColorInterpolator; private final FlingAnimationUtils mFlingAnimationUtils; - private final Drawable mArrowDrawable; - private final int mHintChevronPadding; private float mCircleRadius; private int mCenterX; private int mCenterY; private ValueAnimator mCircleAnimator; private ValueAnimator mAlphaAnimator; private ValueAnimator mScaleAnimator; - private ValueAnimator mArrowAnimator; private float mCircleStartValue; private boolean mCircleWillBeHidden; private int[] mTempPoint = new int[2]; private float mImageScale; private int mCircleColor; private boolean mIsLeft; - private float mArrowAlpha = 0.0f; private View mPreviewView; private float mCircleStartRadius; private float mMaxCircleSize; @@ -113,12 +109,6 @@ public class KeyguardAffordanceView extends ImageView { mAlphaAnimator = null; } }; - private AnimatorListenerAdapter mArrowEndListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mArrowAnimator = null; - } - }; public KeyguardAffordanceView(Context context) { this(context, null); @@ -144,17 +134,12 @@ public class KeyguardAffordanceView extends ImageView { mInverseColor = 0xff000000; mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( R.dimen.keyguard_affordance_min_background_radius); - mHintChevronPadding = mContext.getResources().getDimensionPixelSize( - R.dimen.hint_chevron_circle_padding); mAppearInterpolator = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in); mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in); mColorInterpolator = new ArgbEvaluator(); mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f); - mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left); - mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(), - mArrowDrawable.getIntrinsicHeight()); } @Override @@ -169,7 +154,6 @@ public class KeyguardAffordanceView extends ImageView { protected void onDraw(Canvas canvas) { mSupportHardware = canvas.isHardwareAccelerated(); drawBackgroundCircle(canvas); - drawArrow(canvas); canvas.save(); canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2); super.onDraw(canvas); @@ -183,22 +167,6 @@ public class KeyguardAffordanceView extends ImageView { } } - private void drawArrow(Canvas canvas) { - if (mArrowAlpha > 0) { - canvas.save(); - canvas.translate(mCenterX, mCenterY); - if (mIsLeft) { - canvas.scale(-1.0f, 1.0f); - } - canvas.translate(- mCircleRadius - mHintChevronPadding - - mArrowDrawable.getIntrinsicWidth() / 2, - - mArrowDrawable.getIntrinsicHeight() / 2); - mArrowDrawable.setAlpha((int) (mArrowAlpha * 255)); - mArrowDrawable.draw(canvas); - canvas.restore(); - } - } - private void updateIconColor() { Drawable drawable = getDrawable().mutate(); float alpha = mCircleRadius / mMinBackgroundRadius; @@ -533,36 +501,6 @@ public class KeyguardAffordanceView extends ImageView { return mCircleRadius; } - public void showArrow(boolean show) { - cancelAnimator(mArrowAnimator); - float targetAlpha = show ? 1.0f : 0.0f; - if (mArrowAlpha == targetAlpha) { - return; - } - ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha); - mArrowAnimator = animator; - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - mArrowAlpha = (float) animation.getAnimatedValue(); - invalidate(); - } - }); - animator.addListener(mArrowEndListener); - Interpolator interpolator = show - ? mAppearInterpolator - : mDisappearInterpolator; - animator.setInterpolator(interpolator); - float durationFactor = Math.abs(mArrowAlpha - targetAlpha); - long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); - animator.setDuration(duration); - animator.start(); - } - - public void setIsLeft(boolean left) { - mIsLeft = left; - } - @Override public boolean performClick() { if (isClickable()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index dec2fc7..8172a4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -67,6 +67,8 @@ public class NotificationContentView extends FrameLayout { private final Paint mFadePaint = new Paint(); private boolean mAnimate; private boolean mIsHeadsUp; + private boolean mShowingLegacyBackground; + private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -421,7 +423,7 @@ public class NotificationContentView extends FrameLayout { public void setDark(boolean dark, boolean fade, long delay) { if (mDark == dark || mContractedChild == null) return; mDark = dark; - mContractedWrapper.setDark(dark, fade, delay); + mContractedWrapper.setDark(dark && !mShowingLegacyBackground, fade, delay); } public void setHeadsUp(boolean headsUp) { @@ -436,4 +438,8 @@ public class NotificationContentView extends FrameLayout { // layout, and saves us some layers. return false; } + + public void setShowingLegacyBackground(boolean showing) { + mShowingLegacyBackground = showing; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 2a8b4ac..dbabe3f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar; import android.app.Notification; +import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; @@ -41,6 +42,8 @@ public class NotificationData { private HeadsUpManager mHeadsUpManager; public static final class Entry { + private static final long LAUNCH_COOLDOWN = 2000; + private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN; public String key; public StatusBarNotification notification; public StatusBarIconView icon; @@ -49,6 +52,7 @@ public class NotificationData { public boolean autoRedacted; // whether the redacted notification was generated by us public boolean legacy; // whether the notification has a legacy, dark background public int targetSdk; + private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; public Entry(StatusBarNotification n, StatusBarIconView ic) { this.key = n.getKey(); @@ -72,6 +76,7 @@ public class NotificationData { // We should fix this at some point. autoRedacted = false; legacy = false; + lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET; if (row != null) { row.reset(); } @@ -92,6 +97,14 @@ public class NotificationData { public View getPublicContentView() { return row.getPublicLayout().getContractedChild(); } + + public void notifyFullScreenIntentLaunched() { + lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime(); + } + + public boolean hasJustLaunchedFullScreenIntent() { + return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN; + } } private final ArrayMap<String, Entry> mEntries = new ArrayMap<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 02e196e..2f63c73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -18,14 +18,12 @@ package com.android.systemui.statusbar; import android.content.Context; import android.content.res.ColorStateList; -import android.database.ContentObserver; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.provider.Settings; import android.telephony.SubscriptionInfo; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -40,6 +38,8 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkControllerImpl; import com.android.systemui.statusbar.policy.SecurityController; +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ import java.util.List; public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback, - SecurityController.SecurityControllerCallback { + SecurityController.SecurityControllerCallback, Tunable { static final String TAG = "SignalClusterView"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -105,14 +105,22 @@ public class SignalClusterView public SignalClusterView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - readBlacklist(); } - private void readBlacklist() { - mBlockAirplane = StatusBarIconController.isBlocked(getContext(), SLOT_AIRPLANE); - mBlockMobile = StatusBarIconController.isBlocked(getContext(), SLOT_MOBILE); - mBlockWifi = StatusBarIconController.isBlocked(getContext(), SLOT_WIFI); - mBlockEthernet = StatusBarIconController.isBlocked(getContext(), SLOT_ETHERNET); + @Override + public void onTuningChanged(String key, String newValue) { + if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) { + return; + } + ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(newValue); + mBlockAirplane = blockList.contains(SLOT_AIRPLANE); + mBlockMobile = blockList.contains(SLOT_MOBILE); + mBlockWifi = blockList.contains(SLOT_WIFI); + mBlockEthernet = blockList.contains(SLOT_ETHERNET); + + // Re-register to get new callbacks. + mNC.removeSignalCallback(SignalClusterView.this); + mNC.addSignalCallback(SignalClusterView.this); } public void setNetworkController(NetworkControllerImpl nc) { @@ -160,12 +168,10 @@ public class SignalClusterView for (PhoneState state : mPhoneStates) { mMobileSignalGroup.addView(state.mMobileGroup); } + TunerService.get(mContext).addTunable(this, StatusBarIconController.ICON_BLACKLIST); apply(); applyIconTint(); - getContext().getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false, - mBlacklistObserver); } @Override @@ -178,7 +184,7 @@ public class SignalClusterView mAirplane = null; mMobileSignalGroup.removeAllViews(); mMobileSignalGroup = null; - getContext().getContentResolver().unregisterContentObserver(mBlacklistObserver); + TunerService.get(mContext).removeTunable(this); super.onDetachedFromWindow(); } @@ -528,14 +534,5 @@ public class SignalClusterView setTint(mMobileType, tint); } } - - private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) { - public void onChange(boolean selfChange) { - readBlacklist(); - // Re-register to get new callbacks. - mNC.removeSignalCallback(SignalClusterView.this); - mNC.addSignalCallback(SignalClusterView.this); - }; - }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 64735ee..0877ff9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -127,10 +127,8 @@ public class KeyguardAffordanceHelper { private void initIcons() { mLeftIcon = mCallback.getLeftIcon(); - mLeftIcon.setIsLeft(true); mCenterIcon = mCallback.getCenterIcon(); mRightIcon = mCallback.getRightIcon(); - mRightIcon.setIsLeft(false); updatePreviews(); } @@ -261,7 +259,6 @@ public class KeyguardAffordanceHelper { private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) { final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon; - targetView.showArrow(true); ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount); animator.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; @@ -277,7 +274,6 @@ public class KeyguardAffordanceHelper { mSwipeAnimator = null; mTargetedView = null; onFinishedListener.run(); - targetView.showArrow(false); } else { startUnlockHintAnimationPhase2(right, onFinishedListener); } @@ -301,14 +297,8 @@ public class KeyguardAffordanceHelper { public void onAnimationEnd(Animator animation) { mSwipeAnimator = null; mTargetedView = null; - targetView.showArrow(false); onFinishedListener.run(); } - - @Override - public void onAnimationStart(Animator animation) { - targetView.showArrow(false); - } }); animator.setInterpolator(mDisappearInterpolator); animator.setDuration(HINT_PHASE2_DURATION); 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 3d57d54..3737d05 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -228,4 +228,9 @@ public class KeyguardBouncer { ensureView(); return mKeyguardView.interceptMediaKey(event); } + + public void notifyKeyguardAuthenticated() { + ensureView(); + mKeyguardView.finish(); + } } 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 4bc317a..9e1af82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -36,6 +36,7 @@ import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import android.widget.TextView; @@ -205,6 +206,10 @@ public class NotificationPanelView extends PanelView implements } }; + /** Interpolator to be used for animations that respond directly to a touch */ + private final Interpolator mTouchResponseInterpolator = + new PathInterpolator(0.3f, 0f, 0.1f, 1f); + public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(!DEBUG); @@ -939,7 +944,7 @@ public class NotificationPanelView extends PanelView implements mQsExpansionFromOverscroll = false; updateQsState(); } - }); + }, false /* isClick */); } private void onQsExpansionStarted() { @@ -998,6 +1003,9 @@ public class NotificationPanelView extends PanelView implements mAfforanceHelper.updatePreviews(); } } + if (keyguardShowing) { + updateDozingVisibilities(false /* animate */); + } resetVerticalPanelPosition(); updateQsState(); } @@ -1387,10 +1395,11 @@ public class NotificationPanelView extends PanelView implements } private void flingSettings(float vel, boolean expand) { - flingSettings(vel, expand, null); + flingSettings(vel, expand, null, false /* isClick */); } - private void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable) { + private void flingSettings(float vel, boolean expand, final Runnable onFinishRunnable, + boolean isClick) { float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight; if (target == mQsExpansionHeight) { mScrollYOverride = -1; @@ -1405,7 +1414,12 @@ public class NotificationPanelView extends PanelView implements } mScrollView.setBlockFlinging(true); ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target); - mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel); + if (isClick) { + animator.setInterpolator(mTouchResponseInterpolator); + animator.setDuration(368); + } else { + mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel); + } if (belowFalsingThreshold) { animator.setDuration(350); } @@ -1867,12 +1881,12 @@ public class NotificationPanelView extends PanelView implements if (v == mHeader) { onQsExpansionStarted(); if (mQsExpanded) { - flingSettings(0 /* vel */, false /* expand */); + flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */); } else if (mQsExpansionEnabled) { EventLogTags.writeSysuiLockscreenGesture( EventLogConstants.SYSUI_TAP_TO_OPEN_QS, 0, 0); - flingSettings(0 /* vel */, true /* expand */); + flingSettings(0 /* vel */, true /* expand */, null, true /* isClick */); } } } @@ -2109,6 +2123,12 @@ public class NotificationPanelView extends PanelView implements public void setDozing(boolean dozing, boolean animate) { if (dozing == mDozing) return; mDozing = dozing; + if (mStatusBarState == StatusBarState.KEYGUARD) { + updateDozingVisibilities(animate); + } + } + + private void updateDozingVisibilities(boolean animate) { if (mDozing) { mKeyguardStatusBar.setVisibility(View.INVISIBLE); mKeyguardBottomArea.setVisibility(View.INVISIBLE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index d5209ea..54bd3e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -229,10 +229,6 @@ public class PanelBar extends FrameLayout { public void onTrackingStarted(PanelView panel) { mTracking = true; - if (DEBUG && panel != mTouchingPanel) { - LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)", - panel, mTouchingPanel); - } } public void onTrackingStopped(PanelView panel, boolean expand) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 7c7bec9..569b918 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -32,7 +32,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -345,8 +344,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private int mNavigationIconHints = 0; private HandlerThread mHandlerThread; - private AssistManager mAssistManager; - // ensure quick settings is disabled until the current user makes it through the setup wizard private boolean mUserSetup = false; private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) { @@ -412,6 +409,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private boolean mWaitingForKeyguardExit; private boolean mDozing; + private boolean mDozingRequested; private boolean mScrimSrcModeEnabled; private Interpolator mLinearInterpolator = new LinearInterpolator(); @@ -826,7 +824,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mAccessibilityController = new AccessibilityController(mContext); mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); mNextAlarmController = new NextAlarmController(mContext); - mKeyguardMonitor = new KeyguardMonitor(); + mKeyguardMonitor = new KeyguardMonitor(mContext); if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor); } @@ -1153,7 +1151,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (shadeEntry == null) { return; } - boolean isHeadsUped = mUseHeadsUp && shouldInterrupt(notification); + boolean isHeadsUped = mUseHeadsUp && shouldInterrupt(shadeEntry); if (isHeadsUped) { mHeadsUpManager.showNotification(shadeEntry); // Mark as seen immediately @@ -1171,6 +1169,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, notification.getKey()); notification.getNotification().fullScreenIntent.send(); + shadeEntry.notifyFullScreenIntentLaunched(); } catch (PendingIntent.CanceledException e) { } } @@ -2045,6 +2044,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION, sbn.getKey()); notification.fullScreenIntent.send(); + entry.entry.notifyFullScreenIntentLaunched(); } catch (PendingIntent.CanceledException e) { } } @@ -2751,6 +2751,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); Runnable runnable = new Runnable() { public void run() { + mAssistManager.hideAssist(); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); int result = ActivityManager.START_CANCELED; @@ -2774,10 +2775,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, Runnable cancelRunnable = new Runnable() { @Override public void run() { - callback.onActivityStarted(ActivityManager.START_CANCELED); + if (callback != null) { + callback.onActivityStarted(ActivityManager.START_CANCELED); + } } }; - executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, afterKeyguardGone); + executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade, + afterKeyguardGone); } public void executeRunnableDismissingKeyguard(final Runnable runnable, @@ -3164,9 +3168,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterQs = (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); - mNetworkController.addSignalCallback(signalCluster); - mNetworkController.addSignalCallback(signalClusterKeyguard); - mNetworkController.addSignalCallback(signalClusterQs); + mNetworkController.removeSignalCallback(signalCluster); + mNetworkController.removeSignalCallback(signalClusterKeyguard); + mNetworkController.removeSignalCallback(signalClusterQs); + if (mQSPanel != null && mQSPanel.getHost() != null) { + mQSPanel.getHost().destroy(); + } } private boolean mDemoModeAllowed; @@ -3473,9 +3480,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private void updateDozingState() { - if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) { - return; - } boolean animate = !mDozing && mDozeScrimController.isPulsing(); mNotificationPanel.setDozing(mDozing, animate); mStackScroller.setDark(mDozing, animate, mScreenOnTouchLocation); @@ -3592,6 +3596,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mState = state; mGroupManager.setStatusBarState(state); mStatusBarWindowManager.setStatusBarState(state); + updateDozing(); } @Override @@ -3907,6 +3912,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } + private void updateDozing() { + mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD; + updateDozingState(); + } + private final class ShadeUpdates { private final ArraySet<String> mVisibleNotifications = new ArraySet<String>(); private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>(); @@ -4012,10 +4022,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private void handleStartDozing(@NonNull Runnable ready) { - if (!mDozing) { - mDozing = true; + if (!mDozingRequested) { + mDozingRequested = true; DozeLog.traceDozing(mContext, mDozing); - updateDozingState(); + updateDozing(); } ready.run(); } @@ -4025,10 +4035,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } private void handleStopDozing() { - if (mDozing) { - mDozing = false; + if (mDozingRequested) { + mDozingRequested = false; DozeLog.traceDozing(mContext, mDozing); - updateDozingState(); + updateDozing(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 0872e06..6a6266e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -162,7 +162,8 @@ public class PhoneStatusBarPolicy { mCast.addCallback(mCastCallback); // hotspot - mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null); + mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, + mContext.getString(R.string.accessibility_status_bar_hotspot)); mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); mHotspot.addCallback(mHotspotCallback); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 0ef0fd9..25a93dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -19,13 +19,9 @@ package com.android.systemui.statusbar.phone; import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Process; -import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; -import android.provider.Settings.Secure; +import android.os.Process; import android.util.Log; import com.android.systemui.R; @@ -35,25 +31,26 @@ import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; import com.android.systemui.qs.tiles.ColorInversionTile; +import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.FlashlightTile; import com.android.systemui.qs.tiles.HotspotTile; import com.android.systemui.qs.tiles.IntentTile; import com.android.systemui.qs.tiles.LocationTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.qs.tiles.WifiTile; -import com.android.systemui.qs.tiles.DndTile; -import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.FlashlightController; +import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.SecurityController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; import java.util.Arrays; @@ -63,7 +60,7 @@ import java.util.List; import java.util.Map; /** Platform implementation of the quick settings tile host **/ -public class QSTileHost implements QSTile.Host { +public class QSTileHost implements QSTile.Host, Tunable { private static final String TAG = "QSTileHost"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -72,8 +69,7 @@ public class QSTileHost implements QSTile.Host { private final Context mContext; private final PhoneStatusBar mStatusBar; private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>(); - private final ArrayList<String> mTileSpecs = new ArrayList<>(); - private final Observer mObserver = new Observer(); + protected final ArrayList<String> mTileSpecs = new ArrayList<>(); private final BluetoothController mBluetooth; private final LocationController mLocation; private final RotationLockController mRotation; @@ -82,7 +78,6 @@ public class QSTileHost implements QSTile.Host { private final HotspotController mHotspot; private final CastController mCast; private final Looper mLooper; - protected final CurrentUserTracker mUserTracker; private final FlashlightController mFlashlight; private final UserSwitcherController mUserSwitcherController; private final KeyguardMonitor mKeyguard; @@ -116,22 +111,11 @@ public class QSTileHost implements QSTile.Host { ht.start(); mLooper = ht.getLooper(); - mUserTracker = new CurrentUserTracker(mContext) { - @Override - public void onUserSwitched(int newUserId) { - recreateTiles(); - for (QSTile<?> tile : mTiles.values()) { - tile.userSwitch(newUserId); - } - mSecurity.onUserSwitched(newUserId); - mNetwork.onUserSwitched(newUserId); - mObserver.register(); - } - }; - recreateTiles(); + TunerService.get(mContext).addTunable(this, TILES_SETTING); + } - mUserTracker.startTracking(); - mObserver.register(); + public void destroy() { + TunerService.get(mContext).removeTunable(this); } @Override @@ -221,10 +205,14 @@ public class QSTileHost implements QSTile.Host { public SecurityController getSecurityController() { return mSecurity; } - - private void recreateTiles() { + + @Override + public void onTuningChanged(String key, String newValue) { + if (!TILES_SETTING.equals(key)) { + return; + } if (DEBUG) Log.d(TAG, "Recreating tiles"); - final List<String> tileSpecs = loadTileSpecs(); + final List<String> tileSpecs = loadTileSpecs(newValue); if (tileSpecs.equals(mTileSpecs)) return; for (Map.Entry<String, QSTile<?>> tile : mTiles.entrySet()) { if (!tileSpecs.contains(tile.getKey())) { @@ -270,11 +258,9 @@ public class QSTileHost implements QSTile.Host { else throw new IllegalArgumentException("Bad tile spec: " + tileSpec); } - protected List<String> loadTileSpecs() { + protected List<String> loadTileSpecs(String tileList) { final Resources res = mContext.getResources(); final String defaultTileList = res.getString(R.string.quick_settings_tiles_default); - String tileList = Secure.getStringForUser(mContext.getContentResolver(), TILES_SETTING, - mUserTracker.getCurrentUserId()); if (tileList == null) { tileList = res.getString(R.string.quick_settings_tiles); if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList); @@ -297,26 +283,4 @@ public class QSTileHost implements QSTile.Host { } return tiles; } - - private class Observer extends ContentObserver { - private boolean mRegistered; - - public Observer() { - super(new Handler(Looper.getMainLooper())); - } - - public void register() { - if (mRegistered) { - mContext.getContentResolver().unregisterContentObserver(this); - } - mContext.getContentResolver().registerContentObserver(Secure.getUriFor(TILES_SETTING), - false, this, mUserTracker.getCurrentUserId()); - mRegistered = true; - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - recreateTiles(); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 181926c..dfc6924 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -110,7 +110,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private NextAlarmController mNextAlarmController; private QSPanel mQSPanel; - private final Rect mClipBounds = new Rect(); private boolean mCaptureValues; @@ -121,6 +120,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL private float mCurrentT; private boolean mShowingDetail; + private boolean mDetailTransitioning; public StatusBarHeaderView(Context context, AttributeSet attrs) { super(context, attrs); @@ -623,7 +623,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL mSettingsButton.setTranslationX(values.settingsTranslation); mSettingsButton.setRotation(values.settingsRotation); applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha); - if (!mShowingDetail) { + if (!mShowingDetail && !mDetailTransitioning) { // Otherwise it needs to stay invisible applyAlpha(mAlarmStatus, values.alarmStatusAlpha); } @@ -706,6 +706,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL @Override public void onShowingDetail(final QSTile.DetailAdapter detail) { + mDetailTransitioning = true; post(new Runnable() { @Override public void run() { @@ -788,6 +789,7 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL if (!in) { v.setVisibility(INVISIBLE); } + mDetailTransitioning = false; } }) .start(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index a268077..067e50e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -20,12 +20,10 @@ import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; -import android.database.ContentObserver; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; -import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.view.View; @@ -44,6 +42,8 @@ import com.android.systemui.R; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; +import com.android.systemui.tuner.TunerService; +import com.android.systemui.tuner.TunerService.Tunable; import java.io.PrintWriter; import java.util.ArrayList; @@ -53,7 +53,7 @@ import java.util.ArrayList; * limited to: notification icons, signal cluster, additional status icons, and clock in the status * bar. */ -public class StatusBarIconController { +public class StatusBarIconController implements Tunable { public static final long DEFAULT_TINT_ANIMATION_DURATION = 120; @@ -95,7 +95,7 @@ public class StatusBarIconController { private long mTransitionDeferringStartTime; private long mTransitionDeferringDuration; - private final ArraySet<String> mIconBlacklist; + private final ArraySet<String> mIconBlacklist = new ArraySet<>(); private final Runnable mTransitionDeferringDoneRunnable = new Runnable() { @Override @@ -126,14 +126,33 @@ public class StatusBarIconController { mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone); mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone); mHandler = new Handler(); - mIconBlacklist = getIconBlacklist(context); updateResources(); - context.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false, - mBlacklistObserver); + TunerService.get(mContext).addTunable(this, ICON_BLACKLIST); } + @Override + public void onTuningChanged(String key, String newValue) { + if (!ICON_BLACKLIST.equals(key)) { + return; + } + mIconBlacklist.clear(); + mIconBlacklist.addAll(getIconBlacklist(newValue)); + ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>(); + // Get all the current views. + for (int i = 0; i < mStatusIcons.getChildCount(); i++) { + views.add((StatusBarIconView) mStatusIcons.getChildAt(i)); + } + // Remove all the icons. + for (int i = views.size() - 1; i >= 0; i--) { + removeSystemIcon(views.get(i).getSlot(), i, i); + } + // Add them all back + for (int i = 0; i < views.size(); i++) { + addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon()); + } + }; + public void updateResources() { mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); @@ -429,29 +448,7 @@ public class StatusBarIconController { mTransitionPending = false; } - private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) { - public void onChange(boolean selfChange) { - mIconBlacklist.clear(); - mIconBlacklist.addAll(getIconBlacklist(mContext)); - ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>(); - // Get all the current views. - for (int i = 0; i < mStatusIcons.getChildCount(); i++) { - views.add((StatusBarIconView) mStatusIcons.getChildAt(i)); - } - // Remove all the icons. - for (int i = views.size() - 1; i >= 0; i--) { - removeSystemIcon(views.get(i).getSlot(), i, i); - } - // Add them all back - for (int i = 0; i < views.size(); i++) { - addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon()); - } - } - }; - - public static ArraySet<String> getIconBlacklist(Context context) { - String blackListStr = Settings.Secure.getString(context.getContentResolver(), - ICON_BLACKLIST); + public static ArraySet<String> getIconBlacklist(String blackListStr) { ArraySet<String> ret = new ArraySet<String>(); if (blackListStr != null) { String[] blacklist = blackListStr.split(","); @@ -463,8 +460,4 @@ public class StatusBarIconController { } return ret; } - - public static boolean isBlocked(Context context, String slot) { - return getIconBlacklist(context).contains(slot); - } } 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 6cb890a..fcf3a9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -447,4 +447,12 @@ public class StatusBarKeyguardViewManager { mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */, false /* delayed */, speedUpFactor); } + + /** + * Notifies that the user has authenticated by other means than using the bouncer, for example, + * fingerprint. + */ + public void notifyKeyguardAuthenticated() { + mBouncer.notifyKeyguardAuthenticated(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index 0b3575f..d4eb553 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -16,21 +16,59 @@ package com.android.systemui.statusbar.policy; +import android.app.ActivityManager; +import android.content.Context; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.systemui.settings.CurrentUserTracker; + import java.util.ArrayList; -public final class KeyguardMonitor { +public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback { private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final Context mContext; + private final CurrentUserTracker mUserTracker; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + + private int mCurrentUser; private boolean mShowing; private boolean mSecure; + private boolean mTrusted; + + private boolean mListening; + + public KeyguardMonitor(Context context) { + mContext = context; + mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext); + mUserTracker = new CurrentUserTracker(mContext) { + @Override + public void onUserSwitched(int newUserId) { + mCurrentUser = newUserId; + updateTrustedState(); + } + }; + } public void addCallback(Callback callback) { mCallbacks.add(callback); + if (mCallbacks.size() != 0 && !mListening) { + mListening = true; + mCurrentUser = ActivityManager.getCurrentUser(); + updateTrustedState(); + mKeyguardUpdateMonitor.registerCallback(this); + mUserTracker.startTracking(); + } } public void removeCallback(Callback callback) { - mCallbacks.remove(callback); + if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) { + mListening = false; + mKeyguardUpdateMonitor.removeCallback(this); + mUserTracker.stopTracking(); + } } public boolean isShowing() { @@ -41,10 +79,28 @@ public final class KeyguardMonitor { return mSecure; } + public boolean isTrusted() { + return mTrusted; + } + public void notifyKeyguardState(boolean showing, boolean secure) { if (mShowing == showing && mSecure == secure) return; mShowing = showing; mSecure = secure; + notifyKeyguardChanged(); + } + + @Override + public void onTrustChanged(int userId) { + updateTrustedState(); + notifyKeyguardChanged(); + } + + private void updateTrustedState() { + mTrusted = mKeyguardUpdateMonitor.getUserHasTrust(mCurrentUser); + } + + private void notifyKeyguardChanged() { for (Callback callback : mCallbacks) { callback.onKeyguardChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index ad27c6e..41fc967 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -411,7 +411,8 @@ public class UserSwitcherController { @Override public int getCount() { boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing() - && mController.mKeyguardMonitor.isSecure(); + && mController.mKeyguardMonitor.isSecure() + && !mController.mKeyguardMonitor.isTrusted(); if (!secureKeyguardShowing) { return mController.mUsers.size(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index eac5e79..c31244c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -96,6 +96,7 @@ public class StackStateAnimator { private ExpandableNotificationRow mChildExpandingView; private int mHeadsUpAppearHeightBottom; private boolean mShadeExpanded; + private ArrayList<View> mChildrenToClearFromOverlay = new ArrayList<>(); public StackStateAnimator(NotificationStackScrollLayout hostLayout) { mHostLayout = hostLayout; @@ -794,6 +795,10 @@ public class StackStateAnimator { private void onAnimationFinished() { mHostLayout.onChildAnimationFinished(); + for (View v : mChildrenToClearFromOverlay) { + mHostLayout.getOverlay().remove(v); + } + mChildrenToClearFromOverlay.clear(); } /** @@ -880,8 +885,20 @@ public class StackStateAnimator { finalState.applyState(changingView, mTmpState); } else if (event.animationType == NotificationStackScrollLayout .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) { - // This item is added, initialize it's properties. mHeadsUpDisappearChildren.add(changingView); + if (mHostLayout.indexOfChild(changingView) == -1) { + // This notification was actually removed, so we need to add it to the overlay + mHostLayout.getOverlay().add(changingView); + ViewState viewState = new ViewState(); + viewState.initFrom(changingView); + viewState.yTranslation = -changingView.getActualHeight(); + // We temporarily enable Y animations, the real filter will be combined + // afterwards anyway + mAnimationFilter.animateY = true; + startViewAnimations(changingView, viewState, 0, + ANIMATION_DURATION_HEADS_UP_DISAPPEAR); + mChildrenToClearFromOverlay.add(changingView); + } } mNewEvents.add(event); } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java new file mode 100644 index 0000000..d9f0598 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.tuner; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceChangeListener; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; +import android.preference.SwitchPreference; +import android.provider.Settings; + +import com.android.systemui.DemoMode; +import com.android.systemui.R; + +public class DemoModeFragment extends PreferenceFragment implements OnPreferenceChangeListener { + + private static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed"; + private static final String DEMO_MODE_ON = "sysui_tuner_demo_on"; + + private static final String[] STATUS_ICONS = { + "volume", + "bluetooth", + "location", + "alarm", + "zen", + "sync", + "tty", + "eri", + "mute", + "speakerphone", + "managed_profile", + }; + + private SwitchPreference mEnabledSwitch; + private SwitchPreference mOnSwitch; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Context context = getContext(); + mEnabledSwitch = new SwitchPreference(context); + mEnabledSwitch.setTitle(R.string.enable_demo_mode); + mEnabledSwitch.setOnPreferenceChangeListener(this); + mOnSwitch = new SwitchPreference(context); + mOnSwitch.setTitle(R.string.show_demo_mode); + mOnSwitch.setEnabled(false); + mOnSwitch.setOnPreferenceChangeListener(this); + + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(context); + screen.addPreference(mEnabledSwitch); + screen.addPreference(mOnSwitch); + setPreferenceScreen(screen); + + updateDemoModeEnabled(); + updateDemoModeOn(); + ContentResolver contentResolver = getContext().getContentResolver(); + contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ALLOWED), false, + mDemoModeObserver); + contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ON), false, + mDemoModeObserver); + } + + @Override + public void onDestroy() { + getContext().getContentResolver().unregisterContentObserver(mDemoModeObserver); + super.onDestroy(); + } + + private void updateDemoModeEnabled() { + boolean enabled = Settings.Global.getInt(getContext().getContentResolver(), + DEMO_MODE_ALLOWED, 0) != 0; + mEnabledSwitch.setChecked(enabled); + mOnSwitch.setEnabled(enabled); + } + + private void updateDemoModeOn() { + boolean enabled = Settings.Global.getInt(getContext().getContentResolver(), + DEMO_MODE_ON, 0) != 0; + mOnSwitch.setChecked(enabled); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == mEnabledSwitch) { + setGlobal(DEMO_MODE_ALLOWED, newValue == Boolean.TRUE ? 1 : 0); + } else if (preference == mOnSwitch) { + if (newValue == Boolean.TRUE) { + startDemoMode(); + } else { + stopDemoMode(); + } + } else { + return false; + } + return true; + } + + private void startDemoMode() { + Intent intent = new Intent(DemoMode.ACTION_DEMO); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_ENTER); + getContext().sendBroadcast(intent); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_CLOCK); + intent.putExtra("hhmm", "0520"); + getContext().sendBroadcast(intent); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_NETWORK); + intent.putExtra("wifi", "show"); + intent.putExtra("mobile", "show"); + intent.putExtra("sims", "1"); + intent.putExtra("nosim", "false"); + intent.putExtra("fully", "true"); + intent.putExtra("level", "4"); + intent.putExtra("datatypel", ""); + getContext().sendBroadcast(intent); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_BATTERY); + intent.putExtra("level", "100"); + intent.putExtra("plugged", "false"); + getContext().sendBroadcast(intent); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_STATUS); + for (String icon : STATUS_ICONS) { + intent.putExtra(icon, "hide"); + } + getContext().sendBroadcast(intent); + + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_NOTIFICATIONS); + intent.putExtra("visible", "false"); + getContext().sendBroadcast(intent); + + setGlobal(DEMO_MODE_ON, 1); + } + + private void stopDemoMode() { + Intent intent = new Intent(DemoMode.ACTION_DEMO); + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); + getContext().sendBroadcast(intent); + setGlobal(DEMO_MODE_ON, 0); + } + + private void setGlobal(String key, int value) { + Settings.Global.putInt(getContext().getContentResolver(), key, value); + } + + private final ContentObserver mDemoModeObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + public void onChange(boolean selfChange) { + updateDemoModeEnabled(); + updateDemoModeOn(); + }; + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java index 9f593fc..7472af9 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java @@ -15,6 +15,7 @@ */ package com.android.systemui.tuner; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Fragment; import android.content.ClipData; @@ -49,6 +50,7 @@ import com.android.systemui.qs.tiles.IntentTile; import com.android.systemui.statusbar.phone.QSTileHost; import com.android.systemui.statusbar.policy.SecurityController; +import java.util.ArrayList; import java.util.List; public class QsTuner extends Fragment implements Callback { @@ -107,6 +109,12 @@ public class QsTuner extends Fragment implements Callback { return mScrollRoot; } + @Override + public void onDestroyView() { + mTileHost.destroy(); + super.onDestroyView(); + } + private void setupDropTarget() { QSTileView tileView = new QSTileView(getContext()); QSTile.State state = new QSTile.State(); @@ -187,7 +195,7 @@ public class QsTuner extends Fragment implements Callback { if (oldTile.equals(newTile)) { return; } - List<String> order = loadTileSpecs(); + List<String> order = new ArrayList<>(mTileSpecs); int index = order.indexOf(oldTile); if (index < 0) { Log.e(TAG, "Can't find " + oldTile); @@ -199,32 +207,33 @@ public class QsTuner extends Fragment implements Callback { } public void remove(String tile) { - List<String> tiles = loadTileSpecs(); + List<String> tiles = new ArrayList<>(mTileSpecs); tiles.remove(tile); setTiles(tiles); } public void add(String tile) { - List<String> tiles = loadTileSpecs(); + List<String> tiles = new ArrayList<>(mTileSpecs); tiles.add(tile); setTiles(tiles); } public void reset() { Secure.putStringForUser(getContext().getContentResolver(), - TILES_SETTING, "default", mUserTracker.getCurrentUserId()); + TILES_SETTING, "default", ActivityManager.getCurrentUser()); } private void setTiles(List<String> tiles) { Secure.putStringForUser(getContext().getContentResolver(), TILES_SETTING, - TextUtils.join(",", tiles), mUserTracker.getCurrentUserId()); + TextUtils.join(",", tiles), ActivityManager.getCurrentUser()); } public void showAddDialog() { - List<String> tiles = loadTileSpecs(); + List<String> tiles = mTileSpecs; String[] defaults = getContext().getString(R.string.quick_settings_tiles_default).split(","); final String[] available = new String[defaults.length + 1 - tiles.size()]; + final String[] availableTiles = new String[available.length]; int index = 0; for (int i = 0; i < defaults.length; i++) { if (tiles.contains(defaults[i])) { @@ -232,8 +241,10 @@ public class QsTuner extends Fragment implements Callback { } int resource = getLabelResource(defaults[i]); if (resource != 0) { + availableTiles[index] = defaults[i]; available[index++] = getContext().getString(resource); } else { + availableTiles[index] = defaults[i]; available[index++] = defaults[i]; } } @@ -243,7 +254,7 @@ public class QsTuner extends Fragment implements Callback { .setItems(available, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which < available.length - 1) { - add(available[which]); + add(availableTiles[which]); } else { showBroadcastTileDialog(); } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java index 8158a68..d4cc56d 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java @@ -15,6 +15,7 @@ */ package com.android.systemui.tuner; +import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.preference.SwitchPreference; @@ -23,28 +24,38 @@ import android.text.TextUtils; import android.util.AttributeSet; import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.tuner.TunerService.Tunable; import java.util.Set; -public class StatusBarSwitch extends SwitchPreference { +public class StatusBarSwitch extends SwitchPreference implements Tunable { + + private Set<String> mBlacklist; public StatusBarSwitch(Context context, AttributeSet attrs) { super(context, attrs); - setChecked(!StatusBarIconController.isBlocked(getContext(), getKey())); + } + + @Override + public void onTuningChanged(String key, String newValue) { + if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) { + return; + } + mBlacklist = StatusBarIconController.getIconBlacklist(newValue); + setChecked(!mBlacklist.contains(getKey())); } @Override protected boolean persistBoolean(boolean value) { - Set<String> blacklist = StatusBarIconController.getIconBlacklist(getContext()); if (!value) { // If not enabled add to blacklist. - if (!blacklist.contains(getKey())) { - blacklist.add(getKey()); - setList(blacklist); + if (!mBlacklist.contains(getKey())) { + mBlacklist.add(getKey()); + setList(mBlacklist); } } else { - if (blacklist != null && blacklist.remove(getKey())) { - setList(blacklist); + if (mBlacklist.remove(getKey())) { + setList(mBlacklist); } } return true; @@ -52,7 +63,7 @@ public class StatusBarSwitch extends SwitchPreference { private void setList(Set<String> blacklist) { ContentResolver contentResolver = getContext().getContentResolver(); - Settings.Secure.putString(contentResolver, StatusBarIconController.ICON_BLACKLIST, - TextUtils.join(",", blacklist)); + Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_BLACKLIST, + TextUtils.join(",", blacklist), ActivityManager.getCurrentUser()); } } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index b40adaf..4a8c2e4 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -26,15 +26,19 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; +import android.preference.PreferenceGroup; import android.preference.SwitchPreference; import android.provider.Settings.System; import android.view.MenuItem; import com.android.systemui.R; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.tuner.TunerService.Tunable; public class TunerFragment extends PreferenceFragment { private static final String KEY_QS_TUNER = "qs_tuner"; + private static final String KEY_DEMO_MODE = "demo_mode"; private static final String KEY_BATTERY_PCT = "battery_pct"; private final SettingObserver mSettingObserver = new SettingObserver(); @@ -55,7 +59,17 @@ public class TunerFragment extends PreferenceFragment { ft.replace(android.R.id.content, new QsTuner(), "QsTuner"); ft.addToBackStack(null); ft.commit(); - return false; + return true; + } + }); + findPreference(KEY_DEMO_MODE).setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.replace(android.R.id.content, new DemoModeFragment(), "DemoMode"); + ft.addToBackStack(null); + ft.commit(); + return true; } }); mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT); @@ -67,12 +81,42 @@ public class TunerFragment extends PreferenceFragment { updateBatteryPct(); getContext().getContentResolver().registerContentObserver( System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); + + registerPrefs(getPreferenceScreen()); } @Override public void onPause() { super.onPause(); getContext().getContentResolver().unregisterContentObserver(mSettingObserver); + + unregisterPrefs(getPreferenceScreen()); + } + + private void registerPrefs(PreferenceGroup group) { + TunerService tunerService = TunerService.get(getContext()); + final int N = group.getPreferenceCount(); + for (int i = 0; i < N; i++) { + Preference pref = group.getPreference(i); + if (pref instanceof StatusBarSwitch) { + tunerService.addTunable((Tunable) pref, StatusBarIconController.ICON_BLACKLIST); + } else if (pref instanceof PreferenceGroup) { + registerPrefs((PreferenceGroup) pref); + } + } + } + + private void unregisterPrefs(PreferenceGroup group) { + TunerService tunerService = TunerService.get(getContext()); + final int N = group.getPreferenceCount(); + for (int i = 0; i < N; i++) { + Preference pref = group.getPreference(i); + if (pref instanceof Tunable) { + tunerService.removeTunable((Tunable) pref); + } else if (pref instanceof PreferenceGroup) { + registerPrefs((PreferenceGroup) pref); + } + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java new file mode 100644 index 0000000..de5aaf6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.tuner; + +import android.app.ActivityManager; +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.util.ArrayMap; + +import com.android.systemui.SystemUI; +import com.android.systemui.SystemUIApplication; +import com.android.systemui.settings.CurrentUserTracker; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +public class TunerService extends SystemUI { + + private final Observer mObserver = new Observer(); + // Map of Uris we listen on to their settings keys. + private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); + // Map of settings keys to the listener. + private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>(); + + private ContentResolver mContentResolver; + private int mCurrentUser; + private CurrentUserTracker mUserTracker; + + @Override + public void start() { + mContentResolver = mContext.getContentResolver(); + putComponent(TunerService.class, this); + + mCurrentUser = ActivityManager.getCurrentUser(); + mUserTracker = new CurrentUserTracker(mContext) { + @Override + public void onUserSwitched(int newUserId) { + mCurrentUser = newUserId; + reloadAll(); + reregisterAll(); + } + }; + mUserTracker.startTracking(); + } + + public void addTunable(Tunable tunable, String... keys) { + for (String key : keys) { + addTunable(tunable, key); + } + } + + private void addTunable(Tunable tunable, String key) { + if (!mTunableLookup.containsKey(key)) { + mTunableLookup.put(key, new ArrayList<Tunable>()); + } + mTunableLookup.get(key).add(tunable); + Uri uri = Settings.Secure.getUriFor(key); + if (!mListeningUris.containsKey(uri)) { + mListeningUris.put(uri, key); + mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); + } + // Send the first state. + String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); + tunable.onTuningChanged(key, value); + } + + public void removeTunable(Tunable tunable) { + for (List<Tunable> list : mTunableLookup.values()) { + list.remove(tunable); + } + } + + protected void reregisterAll() { + if (mListeningUris.size() == 0) { + return; + } + mContentResolver.unregisterContentObserver(mObserver); + for (Uri uri : mListeningUris.keySet()) { + mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser); + } + } + + public void reloadSetting(Uri uri) { + String key = mListeningUris.get(uri); + String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); + for (Tunable tunable : mTunableLookup.get(key)) { + tunable.onTuningChanged(key, value); + } + } + + private void reloadAll() { + for (String key : mTunableLookup.keySet()) { + String value = Settings.Secure.getStringForUser(mContentResolver, key, + mCurrentUser); + for (Tunable tunable : mTunableLookup.get(key)) { + tunable.onTuningChanged(key, value); + } + } + } + + // Only used in other processes, such as the tuner. + private static TunerService sInstance; + + public static TunerService get(Context context) { + SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext(); + TunerService service = sysUi.getComponent(TunerService.class); + if (service == null) { + // Can't get it as a component, must in the tuner, lets just create one for now. + return getStaticService(context); + } + return service; + } + + private static TunerService getStaticService(Context context) { + if (sInstance == null) { + sInstance = new TunerService(); + sInstance.mContext = context.getApplicationContext(); + sInstance.mComponents = new HashMap<>(); + sInstance.start(); + } + return sInstance; + } + + private class Observer extends ContentObserver { + public Observer() { + super(new Handler(Looper.getMainLooper())); + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (userId == ActivityManager.getCurrentUser()) { + reloadSetting(uri); + } + } + } + + public interface Tunable { + void onTuningChanged(String key, String newValue); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java index f7cb9fe..81461bd 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java +++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java @@ -36,6 +36,7 @@ public class SegmentedButtons extends LinearLayout { private final Context mContext; private final LayoutInflater mInflater; + private final SpTexts mSpTexts; private Callback mCallback; private Object mSelectedValue; @@ -45,6 +46,7 @@ public class SegmentedButtons extends LinearLayout { mContext = context; mInflater = LayoutInflater.from(mContext); setOrientation(HORIZONTAL); + mSpTexts = new SpTexts(mContext); } public void setCallback(Callback callback) { @@ -68,10 +70,11 @@ public class SegmentedButtons extends LinearLayout { fireOnSelected(); } - public void addButton(int labelResId, Object value) { + public void addButton(int labelResId, int contentDescriptionResId, Object value) { final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false); b.setTag(LABEL_RES_KEY, labelResId); b.setText(labelResId); + b.setContentDescription(getResources().getString(contentDescriptionResId)); final LayoutParams lp = (LayoutParams) b.getLayoutParams(); if (getChildCount() == 0) { lp.leftMargin = lp.rightMargin = 0; // first button has no margin @@ -86,6 +89,7 @@ public class SegmentedButtons extends LinearLayout { fireInteraction(); } }); + mSpTexts.add(b); } public void updateLocale() { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 310a64c..29bea4d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -386,18 +386,8 @@ public class VolumeDialog { } } } else { - if (mAutomute && !row.ss.muteSupported) { - final boolean vmute = row.ss.level == 0; - mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0); - } else { - final boolean mute = !row.ss.muted; - mController.setStreamMute(stream, mute); - if (mAutomute) { - if (!mute && row.ss.level == 0) { - mController.setStreamVolume(stream, 1); - } - } - } + final boolean vmute = row.ss.level == 0; + mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0); } row.userAttempt = 0; // reset the grace period, slider should update immediately } @@ -589,6 +579,9 @@ public class VolumeDialog { if (ss.level > 0) { row.lastAudibleLevel = ss.level; } + if (ss.level == row.requestedLevel) { + row.requestedLevel = -1; + } final boolean isRingStream = row.stream == AudioManager.STREAM_RING; final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM; final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM; @@ -664,7 +657,10 @@ public class VolumeDialog { row.icon.setContentDescription(ss.name); // update slider - updateVolumeRowSliderH(row, zenMuted); + final boolean enableSlider = !zenMuted; + final int vlevel = row.ss.muted && (isRingVibrate || !isRingStream && !zenMuted) ? 0 + : row.ss.level; + updateVolumeRowSliderH(row, enableSlider, vlevel); } private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) { @@ -676,8 +672,8 @@ public class VolumeDialog { row.slider.setThumbTintList(tint); } - private void updateVolumeRowSliderH(VolumeRow row, boolean zenMuted) { - row.slider.setEnabled(!zenMuted); + private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) { + row.slider.setEnabled(enable); updateVolumeRowSliderTintH(row, row.stream == mActiveStream); if (row.tracking) { return; // don't update if user is sliding @@ -694,7 +690,6 @@ public class VolumeDialog { row.userAttempt + USER_ATTEMPT_GRACE_PERIOD); return; // don't update if visible and in grace period } - final int vlevel = row.ss.muted ? 0 : row.ss.level; if (vlevel == level) { if (mShowing && rowVisible) { return; // don't clamp if visible @@ -1018,7 +1013,7 @@ public class VolumeDialog { private StreamState ss; private long userAttempt; // last user-driven slider change private boolean tracking; // tracking slider touch - private int requestedLevel; + private int requestedLevel = -1; // pending user-requested level via progress changed private int iconRes; private int iconMuteRes; private boolean important; diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index 027d637..ced1a3c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -89,6 +89,7 @@ public class ZenModePanel extends LinearLayout { private final IconPulser mIconPulser; private final TransitionHelper mTransitionHelper = new TransitionHelper(); private final Uri mForeverId; + private final SpTexts mSpTexts; private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this)); @@ -96,7 +97,7 @@ public class ZenModePanel extends LinearLayout { private View mZenIntroduction; private TextView mZenIntroductionMessage; private View mZenIntroductionConfirm; - private View mZenIntroductionCustomize; + private TextView mZenIntroductionCustomize; private LinearLayout mZenConditions; private TextView mZenAlarmWarning; @@ -125,6 +126,7 @@ public class ZenModePanel extends LinearLayout { mInflater = LayoutInflater.from(mContext.getApplicationContext()); mIconPulser = new IconPulser(mContext); mForeverId = Condition.newId(mContext).appendPath("forever").build(); + mSpTexts = new SpTexts(mContext); if (DEBUG) Log.d(mTag, "new ZenModePanel"); } @@ -151,15 +153,19 @@ public class ZenModePanel extends LinearLayout { mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons); mZenButtons.addButton(R.string.interruption_level_none_twoline, + R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS); mZenButtons.addButton(R.string.interruption_level_alarms_twoline, + R.string.interruption_level_alarms, Global.ZEN_MODE_ALARMS); mZenButtons.addButton(R.string.interruption_level_priority_twoline, + R.string.interruption_level_priority, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); mZenButtons.setCallback(mZenButtonsCallback); mZenIntroduction = findViewById(R.id.zen_introduction); mZenIntroductionMessage = (TextView) findViewById(R.id.zen_introduction_message); + mSpTexts.add(mZenIntroductionMessage); mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm); mZenIntroductionConfirm.setOnClickListener(new OnClickListener() { @Override @@ -167,7 +173,7 @@ public class ZenModePanel extends LinearLayout { confirmZenIntroduction(); } }); - mZenIntroductionCustomize = findViewById(R.id.zen_introduction_customize); + mZenIntroductionCustomize = (TextView) findViewById(R.id.zen_introduction_customize); mZenIntroductionCustomize.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -177,6 +183,7 @@ public class ZenModePanel extends LinearLayout { } } }); + mSpTexts.add(mZenIntroductionCustomize); mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning); @@ -658,9 +665,11 @@ public class ZenModePanel extends LinearLayout { } if (tag.line1 == null) { tag.line1 = (TextView) row.findViewById(android.R.id.text1); + mSpTexts.add(tag.line1); } if (tag.line2 == null) { tag.line2 = (TextView) row.findViewById(android.R.id.text2); + mSpTexts.add(tag.line2); } final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1 : condition.summary; |
