summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java191
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java325
22 files changed, 623 insertions, 267 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index ce0d5f4..a311d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -18,13 +18,13 @@ package com.android.systemui.qs;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -162,6 +162,12 @@ public class QSDetailItems extends FrameLayout {
view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
iv.setImageResource(item.icon);
+ iv.getOverlay().clear();
+ if (item.overlay != null) {
+ item.overlay.setBounds(0, 0, item.overlay.getIntrinsicWidth(),
+ item.overlay.getIntrinsicHeight());
+ iv.getOverlay().add(item.overlay);
+ }
final TextView title = (TextView) view.findViewById(android.R.id.title);
title.setText(item.line1);
final TextView summary = (TextView) view.findViewById(android.R.id.summary);
@@ -213,6 +219,7 @@ public class QSDetailItems extends FrameLayout {
public static class Item {
public int icon;
+ public Drawable overlay;
public String line1;
public String line2;
public Object tag;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 699240c..a920624 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -326,7 +326,12 @@ public class WifiTile extends QSTile<QSTile.SignalState> {
item.line2 = mContext.getString(ap.isConfigured ?
R.string.quick_settings_connected :
R.string.quick_settings_connected_via_wfa);
+ } else if (ap.networkId >= 0) {
+ // TODO: Set line 2 to wifi saved string here.
}
+ item.overlay = ap.hasSecurity
+ ? mContext.getDrawable(R.drawable.qs_ic_wifi_lock)
+ : null;
items[i] = item;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 4f0700e..f1bf66d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -61,15 +61,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
/** A proxy implementation for the recents component */
public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
- final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
- final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome";
- final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
- final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId";
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey";
- final public static String EXTRA_REUSE_TASK_STACK_VIEWS = "recents.reuseTaskStackViews";
- final public static String EXTRA_NUM_VISIBLE_TASKS = "recents.numVisibleTasks";
- final public static String EXTRA_NUM_VISIBLE_THUMBNAILS = "recents.numVisibleThumbnails";
final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation";
final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity";
@@ -550,7 +543,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
mDummyStackView);
if (opts != null) {
- startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL, stackVr);
+ startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
+ false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
@@ -583,12 +577,13 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
}
ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
- startAlternateRecentsActivity(topTask, opts,
- fromSearchHome ? EXTRA_FROM_SEARCH_HOME : EXTRA_FROM_HOME, stackVr);
+ startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+ false /* fromThumbnail */, stackVr);
} else {
// Otherwise we do the normal fade from an unknown source
ActivityOptions opts = getUnknownTransitionActivityOptions();
- startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME, stackVr);
+ startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+ false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
}
}
mLastToggleTime = SystemClock.elapsedRealtime();
@@ -596,21 +591,24 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
/** Starts the recents activity */
void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
- ActivityOptions opts, String extraFlag,
+ ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+ // Update the configuration based on the launch options
+ mConfig.launchedFromHome = fromSearchHome || fromHome;
+ mConfig.launchedFromSearchHome = fromSearchHome;
+ mConfig.launchedFromAppWithThumbnail = fromThumbnail;
+ mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+ mConfig.launchedWithAltTab = mTriggeredFromAltTab;
+ mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+ mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
+ mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+ mConfig.launchedHasConfigurationChanged = false;
+
Intent intent = new Intent(sToggleRecentsAction);
intent.setClassName(sRecentsPackage, sRecentsActivity);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- if (extraFlag != null) {
- intent.putExtra(extraFlag, true);
- }
- intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
- intent.putExtra(EXTRA_FROM_TASK_ID, (topTask != null) ? topTask.id : -1);
- intent.putExtra(EXTRA_REUSE_TASK_STACK_VIEWS, mCanReuseTaskStackViews);
- intent.putExtra(EXTRA_NUM_VISIBLE_TASKS, vr.numVisibleTasks);
- intent.putExtra(EXTRA_NUM_VISIBLE_THUMBNAILS, vr.numVisibleThumbnails);
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index a37bc54..6baff96 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -108,8 +108,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void run() {
- // Mark Recents as no longer visible
- onRecentsActivityVisibilityChanged(false);
// Finish Recents
if (mLaunchIntent != null) {
if (mLaunchOpts != null) {
@@ -133,8 +131,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
- // Mark Recents as no longer visible
- AlternateRecentsComponent.notifyVisibilityChanged(false);
if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
// If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
dismissRecentsToFocusedTaskOrHome(false);
@@ -186,24 +182,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
/** Updates the set of recent tasks */
void updateRecentsTasks(Intent launchIntent) {
- // Update the configuration based on the launch intent
- boolean fromSearchHome = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_FROM_SEARCH_HOME, false);
- int numVisibleTasks = launchIntent.getIntExtra(
- AlternateRecentsComponent.EXTRA_NUM_VISIBLE_TASKS, 0);
- int numVisibleThumbnails = launchIntent.getIntExtra(
- AlternateRecentsComponent.EXTRA_NUM_VISIBLE_THUMBNAILS, 0);
- mConfig.launchedFromHome = fromSearchHome || launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_FROM_HOME, false);
- mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
- mConfig.launchedToTaskId = launchIntent.getIntExtra(
- AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1);
- mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
- mConfig.launchedReuseTaskStackViews = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_REUSE_TASK_STACK_VIEWS, false);
-
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -218,8 +196,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
loadOpts.runningTaskId = mConfig.launchedToTaskId;
- loadOpts.numVisibleTasks = numVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = numVisibleThumbnails;
+ loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
loader.loadTasks(this, plan, loadOpts);
SpaceNode root = plan.getSpaceNode();
@@ -237,9 +215,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
ActivityOptions.makeCustomAnimation(this,
- fromSearchHome ? R.anim.recents_to_search_launcher_enter :
+ mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
R.anim.recents_to_launcher_enter,
- fromSearchHome ? R.anim.recents_to_search_launcher_exit :
+ mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
R.anim.recents_to_launcher_exit));
// Mark the task that is the launch target
@@ -403,12 +381,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
mScrimViews = new SystemBarScrimViews(this, mConfig);
+ mStatusBar = ((SystemUIApplication) getApplication())
+ .getComponent(PhoneStatusBar.class);
inflateDebugOverlay();
// Bind the search app widget when we first start up
bindSearchBarAppWidget();
- // Update the recent tasks
- updateRecentsTasks(getIntent());
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
@@ -424,17 +402,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
} catch (InvocationTargetException e) {
e.printStackTrace();
}
-
- // Update if we are getting a configuration change
- if (savedInstanceState != null) {
- // Update RecentsConfiguration
- mConfig.updateOnConfigurationChange();
- // Trigger the enter animation
- onEnterAnimationTriggered();
- }
-
- mStatusBar = ((SystemUIApplication) getApplication())
- .getComponent(PhoneStatusBar.class);
}
/** Inflates the debug overlay if debug mode is enabled. */
@@ -449,14 +416,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
}
}
- /** Handles changes to the activity visibility. */
- void onRecentsActivityVisibilityChanged(boolean visible) {
- if (!visible) {
- AlternateRecentsComponent.notifyVisibilityChanged(visible);
- }
- mVisible = visible;
- }
-
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -469,14 +428,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
if (mDebugOverlay != null) {
mDebugOverlay.clear();
}
-
- // Update the recent tasks
- updateRecentsTasks(intent);
}
@Override
protected void onStart() {
super.onStart();
+ mVisible = true;
+ AlternateRecentsComponent.notifyVisibilityChanged(true);
// Register the broadcast receiver to handle messages from our service
IntentFilter filter = new IntentFilter();
@@ -487,19 +445,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
// Register any broadcast receivers for the task loader
RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- // Mark Recents as visible
- onRecentsActivityVisibilityChanged(true);
+ // Update the recent tasks
+ updateRecentsTasks(getIntent());
}
@Override
protected void onStop() {
super.onStop();
+ mVisible = false;
+ AlternateRecentsComponent.notifyVisibilityChanged(false);
// Notify the views that we are no longer visible
mRecentsView.onRecentsHidden();
@@ -641,8 +596,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
@Override
public void onTaskViewClicked() {
- // Mark recents as no longer visible
- onRecentsActivityVisibilityChanged(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 2b33d14..52e7e7f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -124,8 +124,12 @@ public class RecentsConfiguration {
public boolean launchedWithNoRecentTasks;
public boolean launchedFromAppWithThumbnail;
public boolean launchedFromHome;
+ public boolean launchedFromSearchHome;
public boolean launchedReuseTaskStackViews;
+ public boolean launchedHasConfigurationChanged;
public int launchedToTaskId;
+ public int launchedNumVisibleTasks;
+ public int launchedNumVisibleThumbnails;
/** Misc **/
public boolean useHardwareLayers;
@@ -308,12 +312,10 @@ public class RecentsConfiguration {
/** Called when the configuration has changed, and we want to reset any configuration specific
* members. */
public void updateOnConfigurationChange() {
- launchedWithAltTab = false;
- launchedWithNoRecentTasks = false;
- launchedFromAppWithThumbnail = false;
- launchedFromHome = false;
+ // Reset this flag on configuration change to ensure that we recreate new task views
launchedReuseTaskStackViews = false;
- launchedToTaskId = -1;
+ // Set this flag to indicate that the configuration has changed since Recents last launched
+ launchedHasConfigurationChanged = true;
}
/** Returns whether the search bar app widget exists. */
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 33a36f6..169683f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -715,14 +715,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mStartEnterAnimationContext = null;
}
- // When Alt-Tabbing, we scroll to and focus the previous task
+ // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
+ // enter animation).
if (mConfig.launchedWithAltTab) {
- if (mConfig.launchedFromHome) {
- focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true);
+ if (mConfig.launchedFromAppWithThumbnail) {
+ focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
+ mConfig.launchedHasConfigurationChanged);
} else {
- focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true);
+ focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
+ mConfig.launchedHasConfigurationChanged);
}
}
+
+ // Start dozing
+ mUIDozeTrigger.startDozing();
}
/** Requests this task stacks to start it's enter-recents animation */
@@ -767,16 +773,27 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
@Override
public void run() {
mStartEnterAnimationCompleted = true;
- // Start dozing
- mUIDozeTrigger.startDozing();
- // Focus the first view if accessibility is enabled
+ // Poke the dozer to restart the trigger after the animation completes
+ mUIDozeTrigger.poke();
+
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SystemServicesProxy ssp = loader.getSystemServicesProxy();
int childCount = getChildCount();
- if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
- TaskView tv = ((TaskView) getChildAt(childCount - 1));
- tv.requestAccessibilityFocus();
- mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+ if (childCount > 0) {
+ // Focus the first view if accessibility is enabled
+ if (ssp.isTouchExplorationEnabled()) {
+ TaskView tv = ((TaskView) getChildAt(childCount - 1));
+ tv.requestAccessibilityFocus();
+ mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+ }
+ }
+
+ // Start the focus animation when alt-tabbing
+ if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
+ View tv = getChildAt(mFocusedTaskIndex);
+ if (tv != null) {
+ ((TaskView) tv).setFocusedTask(true);
+ }
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 26fbbf4..49b9129 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -135,7 +135,6 @@ public class TaskStackViewLayoutAlgorithm {
// Update the task offsets
float pAtBackMostCardTop = 0.5f;
float pAtFrontMostCardTop = pAtBackMostCardTop;
- float pAtSecondFrontMostCardTop = pAtBackMostCardTop;
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
@@ -145,25 +144,19 @@ public class TaskStackViewLayoutAlgorithm {
// Increment the peek height
float pPeek = task.group.isFrontMostTask(task) ?
pBetweenAffiliateOffset : pWithinAffiliateOffset;
- pAtSecondFrontMostCardTop = pAtFrontMostCardTop;
pAtFrontMostCardTop += pPeek;
}
}
mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset));
mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f;
- if (launchedWithAltTab) {
- if (launchedFromHome) {
- // Center the top most task, since that will be focused first
- mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
- } else {
- // Center the second top most task, since that will be focused first
- mInitialScrollP = pAtSecondFrontMostCardTop - 0.5f;
- }
+ if (launchedWithAltTab && launchedFromHome) {
+ // Center the top most task, since that will be focused first
+ mInitialScrollP = mMaxScrollP;
} else {
mInitialScrollP = pAtFrontMostCardTop - 0.825f;
}
- mInitialScrollP = Math.max(0, mInitialScrollP);
+ mInitialScrollP = Math.min(mMaxScrollP, Math.max(0, mInitialScrollP));
}
/**
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 de5974f..faa728d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -235,7 +235,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
boolean occludesLaunchTarget, int offscreenY) {
int initialDim = getDim();
- if (mConfig.launchedFromAppWithThumbnail) {
+ if (mConfig.launchedHasConfigurationChanged) {
+ // Just load the views as-is
+ } else if (mConfig.launchedFromAppWithThumbnail) {
if (isTaskViewLaunchTargetTask) {
// Set the dim to 0 so we can animate it in
initialDim = 0;
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 464d007..05f6f40 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -237,15 +237,17 @@ public class TaskViewHeader extends FrameLayout {
/** Animates this task bar if the user does not interact with the stack after a certain time. */
void startNoUserInteractionAnimation() {
- mDismissButton.setVisibility(View.VISIBLE);
- mDismissButton.setAlpha(0f);
- mDismissButton.animate()
- .alpha(1f)
- .setStartDelay(0)
- .setInterpolator(mConfig.fastOutLinearInInterpolator)
- .setDuration(mConfig.taskViewEnterFromAppDuration)
- .withLayer()
- .start();
+ if (mDismissButton.getVisibility() != View.VISIBLE) {
+ mDismissButton.setVisibility(View.VISIBLE);
+ mDismissButton.setAlpha(0f);
+ mDismissButton.animate()
+ .alpha(1f)
+ .setStartDelay(0)
+ .setInterpolator(mConfig.fastOutLinearInInterpolator)
+ .setDuration(mConfig.taskViewEnterFromAppDuration)
+ .withLayer()
+ .start();
+ }
}
/** Mark this task view that the user does has not interacted with the stack after a certain time. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 0faad21..914b3d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -124,6 +124,7 @@ public class NotificationContentView extends FrameLayout {
mContractedChild = child;
mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
selectLayout(false /* animate */, true /* force */);
+ mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
}
public void setExpandedChild(View child) {
@@ -245,6 +246,7 @@ public class NotificationContentView extends FrameLayout {
public void notifyContentUpdated() {
selectLayout(false /* animate */, true /* force */);
if (mContractedChild != null) {
+ mContractedWrapper.notifyContentUpdated();
mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index 5b6e1cd..fbcba0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -26,6 +26,7 @@ import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -40,17 +41,18 @@ import com.android.systemui.statusbar.phone.NotificationPanelView;
*/
public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
- private final ViewInvertHelper mInvertHelper;
- private final ImageView mIcon;
- protected final ImageView mPicture;
private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
0, PorterDuff.Mode.SRC_ATOP);
private final int mIconDarkAlpha;
- private final int mIconBackgroundColor;
private final int mIconBackgroundDarkColor;
private final Interpolator mLinearOutSlowInInterpolator;
+ private int mIconBackgroundColor;
+ private ViewInvertHelper mInvertHelper;
+ private ImageView mIcon;
+ protected ImageView mPicture;
+
protected NotificationTemplateViewWrapper(Context ctx, View view) {
super(view);
mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
@@ -58,12 +60,16 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
ctx.getResources().getColor(R.color.doze_small_icon_background_color);
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
android.R.interpolator.linear_out_slow_in);
- View mainColumn = view.findViewById(com.android.internal.R.id.notification_main_column);
+ resolveViews();
+ }
+
+ private void resolveViews() {
+ View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
mInvertHelper = mainColumn != null
? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION)
: null;
- ImageView largeIcon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
- ImageView rightIcon = (ImageView) view.findViewById(com.android.internal.R.id.right_icon);
+ ImageView largeIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+ ImageView rightIcon = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
mIcon = resolveIcon(largeIcon, rightIcon);
mPicture = resolvePicture(largeIcon);
mIconBackgroundColor = resolveBackgroundColor(mIcon);
@@ -92,6 +98,14 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
}
@Override
+ public void notifyContentUpdated() {
+ super.notifyContentUpdated();
+
+ // Reinspect the notification.
+ resolveViews();
+ }
+
+ @Override
public void setDark(boolean dark, boolean fade, long delay) {
if (mInvertHelper != null) {
if (fade) {
@@ -180,7 +194,13 @@ public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
private void updateIconColorFilter(ImageView target, float intensity) {
int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity);
mIconColorFilter.setColor(color);
- target.getBackground().mutate().setColorFilter(mIconColorFilter);
+ Drawable background = target.getBackground();
+
+ // The notification might have been modified during the animation, so background might be
+ // null here.
+ if (background != null) {
+ background.mutate().setColorFilter(mIconColorFilter);
+ }
}
private void updateIconAlpha(ImageView target, boolean dark) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 0a02573..78b9739 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -53,4 +53,9 @@ public abstract class NotificationViewWrapper {
* @param delay if fading, the delay of the animation
*/
public abstract void setDark(boolean dark, boolean fade, long delay);
+
+ /**
+ * Notifies this wrapper that the content of the view might have changed.
+ */
+ public void notifyContentUpdated() {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 8e50abe..8e35ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -277,9 +277,13 @@ public class SignalClusterView
mWifiStrengthId));
boolean anyMobileVisible = false;
+ int firstMobileTypeId = 0;
for (PhoneState state : mPhoneStates) {
if (state.apply(anyMobileVisible)) {
- anyMobileVisible = true;
+ if (!anyMobileVisible) {
+ firstMobileTypeId = state.mMobileTypeId;
+ anyMobileVisible = true;
+ }
}
}
@@ -298,7 +302,7 @@ public class SignalClusterView
mWifiAirplaneSpacer.setVisibility(View.GONE);
}
- if ((anyMobileVisible || mNoSimsVisible) && mWifiVisible) {
+ if (((anyMobileVisible && firstMobileTypeId != 0) || mNoSimsVisible) && mWifiVisible) {
mWifiSignalSpacer.setVisibility(View.VISIBLE);
} else {
mWifiSignalSpacer.setVisibility(View.GONE);
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 08844f3..d2dc425 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1629,6 +1629,7 @@ public class NotificationPanelView extends PanelView implements
} else {
mSecureCameraLaunchManager.startSecureCameraLaunch();
}
+ mStatusBar.startLaunchTransitionTimeout();
mBlockTouches = true;
}
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 ec2d30c..8b328aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -203,8 +203,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
private static final int MSG_CLOSE_PANELS = 1001;
private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
+ private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
// 1020-1040 reserved for BaseStatusBar
+ // Time after we abort the launch transition.
+ private static final long LAUNCH_TRANSITION_TIMEOUT_MS = 5000;
+
private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
@@ -2196,6 +2200,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
escalateHeadsUp();
setHeadsUpVisibility(false);
break;
+ case MSG_LAUNCH_TRANSITION_TIMEOUT:
+ onLaunchTransitionTimeout();
+ break;
}
}
}
@@ -3528,12 +3535,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mLaunchTransitionFadingAway) {
mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
- if (mLaunchTransitionEndRunnable != null) {
- mLaunchTransitionEndRunnable.run();
- }
- mLaunchTransitionEndRunnable = null;
+ runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
}
+ mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
setBarState(StatusBarState.KEYGUARD);
updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
if (!mScreenOnFromKeyguard) {
@@ -3574,6 +3579,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
*/
public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
Runnable endRunnable) {
+ mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
mLaunchTransitionEndRunnable = endRunnable;
Runnable hideRunnable = new Runnable() {
@Override
@@ -3592,10 +3598,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void run() {
mNotificationPanel.setAlpha(1);
- if (mLaunchTransitionEndRunnable != null) {
- mLaunchTransitionEndRunnable.run();
- }
- mLaunchTransitionEndRunnable = null;
+ runLaunchTransitionEndRunnable();
mLaunchTransitionFadingAway = false;
}
});
@@ -3609,6 +3612,32 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
/**
+ * Starts the timeout when we try to start the affordances on Keyguard. We usually rely that
+ * Keyguard goes away via fadeKeyguardAfterLaunchTransition, however, that might not happen
+ * because the launched app crashed or something else went wrong.
+ */
+ public void startLaunchTransitionTimeout() {
+ mHandler.sendEmptyMessageDelayed(MSG_LAUNCH_TRANSITION_TIMEOUT,
+ LAUNCH_TRANSITION_TIMEOUT_MS);
+ }
+
+ private void onLaunchTransitionTimeout() {
+ Log.w(TAG, "Launch transition: Timeout!");
+ mNotificationPanel.resetViews();
+ }
+
+ private void runLaunchTransitionEndRunnable() {
+ if (mLaunchTransitionEndRunnable != null) {
+ Runnable r = mLaunchTransitionEndRunnable;
+
+ // mLaunchTransitionEndRunnable might call showKeyguard, which would execute it again,
+ // which would lead to infinite recursion. Protect against it.
+ mLaunchTransitionEndRunnable = null;
+ r.run();
+ }
+ }
+
+ /**
* @return true if we would like to stay in the shade, false if it should go away entirely
*/
public boolean hideKeyguard() {
@@ -3631,6 +3660,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (mQSPanel != null) {
mQSPanel.refreshAllTiles();
}
+ mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
return staying;
}
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 77da70a..f4edab5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -199,7 +199,7 @@ public class StatusBarKeyguardViewManager {
new Runnable() {
@Override
public void run() {
- mStatusBarWindowManager.setKeyguardOccluded(true);
+ mStatusBarWindowManager.setKeyguardOccluded(mOccluded);
reset();
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 80fec5b..076cfe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -19,15 +19,21 @@ package com.android.systemui.statusbar.policy;
import static android.bluetooth.BluetoothAdapter.ERROR;
import static com.android.systemui.statusbar.policy.BluetoothUtil.connectionStateToString;
import static com.android.systemui.statusbar.policy.BluetoothUtil.deviceToString;
-import static com.android.systemui.statusbar.policy.BluetoothUtil.profileStateToString;
import static com.android.systemui.statusbar.policy.BluetoothUtil.profileToString;
import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToProfile;
import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidToString;
import static com.android.systemui.statusbar.policy.BluetoothUtil.uuidsToString;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.BroadcastReceiver;
@@ -38,24 +44,37 @@ import android.os.ParcelUuid;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.SparseBooleanArray;
+import android.util.SparseArray;
import com.android.systemui.statusbar.policy.BluetoothUtil.Profile;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
public class BluetoothControllerImpl implements BluetoothController {
private static final String TAG = "BluetoothController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ // This controls the order in which we check the states. Since a device can only have
+ // one state on screen, but can have multiple profiles, the later states override the
+ // value of earlier states. So if a device has a profile in CONNECTING and one in
+ // CONNECTED, it will show as CONNECTED, theoretically this shouldn't really happen often,
+ // but seemed worth noting.
+ private static final int[] CONNECTION_STATES = {
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING,
+ BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_CONNECTED,
+ };
private final Context mContext;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final BluetoothAdapter mAdapter;
private final Receiver mReceiver = new Receiver();
private final ArrayMap<BluetoothDevice, DeviceInfo> mDeviceInfo = new ArrayMap<>();
+ private final SparseArray<BluetoothProfile> mProfiles = new SparseArray<>();
private boolean mEnabled;
private boolean mConnecting;
@@ -73,7 +92,8 @@ public class BluetoothControllerImpl implements BluetoothController {
mReceiver.register();
setAdapterState(mAdapter.getState());
- updateBondedBluetoothDevices();
+ updateBluetoothDevices();
+ bindAllProfiles();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -83,6 +103,7 @@ public class BluetoothControllerImpl implements BluetoothController {
pw.print(" mConnecting="); pw.println(mConnecting);
pw.print(" mLastDevice="); pw.println(mLastDevice);
pw.print(" mCallbacks.size="); pw.println(mCallbacks.size());
+ pw.print(" mProfiles="); pw.println(profilesToString(mProfiles));
pw.print(" mDeviceInfo.size="); pw.println(mDeviceInfo.size());
for (int i = 0; i < mDeviceInfo.size(); i++) {
final BluetoothDevice device = mDeviceInfo.keyAt(i);
@@ -95,7 +116,22 @@ public class BluetoothControllerImpl implements BluetoothController {
private static String infoToString(DeviceInfo info) {
return info == null ? null : ("connectionState=" +
- connectionStateToString(info.connectionState) + ",bonded=" + info.bonded);
+ connectionStateToString(info.connectionState) + ",bonded=" + info.bonded
+ + ",profiles=" + profilesToString(info.connectedProfiles));
+ }
+
+ private static String profilesToString(SparseArray<?> profiles) {
+ final int N = profiles.size();
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append('[');
+ for (int i = 0; i < N; i++) {
+ if (i != 0) {
+ buffer.append(',');
+ }
+ buffer.append(BluetoothUtil.profileToString(profiles.keyAt(i)));
+ }
+ buffer.append(']');
+ return buffer.toString();
}
public void addStateChangedCallback(Callback cb) {
@@ -178,6 +214,7 @@ public class BluetoothControllerImpl implements BluetoothController {
private void connect(PairedDevice pd, final boolean connect) {
if (mAdapter == null || pd == null || pd.tag == null) return;
final BluetoothDevice device = (BluetoothDevice) pd.tag;
+ final DeviceInfo info = mDeviceInfo.get(device);
final String action = connect ? "connect" : "disconnect";
if (DEBUG) Log.d(TAG, action + " " + deviceToString(device));
final ParcelUuid[] uuids = device.getUuids();
@@ -185,43 +222,35 @@ public class BluetoothControllerImpl implements BluetoothController {
Log.w(TAG, "No uuids returned, aborting " + action + " for " + deviceToString(device));
return;
}
- final SparseBooleanArray profiles = new SparseBooleanArray();
- for (ParcelUuid uuid : uuids) {
- final int profile = uuidToProfile(uuid);
- if (profile == 0) {
- Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: "
- + uuidToString(uuid));
- continue;
- }
- final int profileState = mAdapter.getProfileConnectionState(profile);
- if (DEBUG && !profiles.get(profile)) Log.d(TAG, "Profile " + profileToString(profile)
- + " state = " + profileStateToString(profileState));
- final boolean connected = profileState == BluetoothProfile.STATE_CONNECTED;
- if (connect != connected) {
- profiles.put(profile, true);
+ SparseArray<Boolean> profiles = new SparseArray<>();
+ if (connect) {
+ // When connecting add every profile we can recognize by uuid.
+ for (ParcelUuid uuid : uuids) {
+ final int profile = uuidToProfile(uuid);
+ if (profile == 0) {
+ Log.w(TAG, "Device " + deviceToString(device) + " has an unsupported uuid: "
+ + uuidToString(uuid));
+ continue;
+ }
+ final boolean connected = info.connectedProfiles.get(profile, false);
+ if (!connected) {
+ profiles.put(profile, true);
+ }
}
+ } else {
+ // When disconnecting, just add every profile we know they are connected to.
+ profiles = info.connectedProfiles;
}
for (int i = 0; i < profiles.size(); i++) {
final int profile = profiles.keyAt(i);
- mAdapter.getProfileProxy(mContext, new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DEBUG) Log.d(TAG, "onServiceConnected " + profileToString(profile));
- final Profile p = BluetoothUtil.getProfile(proxy);
- if (p == null) {
- Log.w(TAG, "Unable get get Profile for " + profileToString(profile));
- } else {
- final boolean ok = connect ? p.connect(device) : p.disconnect(device);
- if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " "
- + (ok ? "succeeded" : "failed"));
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (DEBUG) Log.d(TAG, "onServiceDisconnected " + profileToString(profile));
- }
- }, profile);
+ if (mProfiles.indexOfKey(profile) >= 0) {
+ final Profile p = BluetoothUtil.getProfile(mProfiles.get(profile));
+ final boolean ok = connect ? p.connect(device) : p.disconnect(device);
+ if (DEBUG) Log.d(TAG, action + " " + profileToString(profile) + " "
+ + (ok ? "succeeded" : "failed"));
+ } else {
+ Log.w(TAG, "Unable get get Profile for " + profileToString(profile));
+ }
}
}
@@ -230,11 +259,13 @@ public class BluetoothControllerImpl implements BluetoothController {
return mLastDevice != null ? mLastDevice.getAliasName() : null;
}
- private void updateBondedBluetoothDevices() {
+ private void updateBluetoothDevices() {
if (mAdapter == null) return;
final Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
for (DeviceInfo info : mDeviceInfo.values()) {
info.bonded = false;
+ info.connectionState = ERROR;
+ info.connectedProfiles.clear();
}
int bondedCount = 0;
BluetoothDevice lastBonded = null;
@@ -248,12 +279,62 @@ public class BluetoothControllerImpl implements BluetoothController {
}
}
}
+ final int N = mProfiles.size();
+ final int[] connectionType = new int[1];
+ for (int i = 0; i < CONNECTION_STATES.length; i++) {
+ connectionType[0] = CONNECTION_STATES[i];
+ for (int j = 0; j < N; j++) {
+ int profile = mProfiles.keyAt(j);
+ List<BluetoothDevice> devices = mProfiles.get(profile)
+ .getDevicesMatchingConnectionStates(connectionType);
+ for (int k = 0; k < devices.size(); k++) {
+ DeviceInfo info = mDeviceInfo.get(devices.get(k));
+ info.connectionState = CONNECTION_STATES[i];
+ if (CONNECTION_STATES[i] == BluetoothProfile.STATE_CONNECTED) {
+ info.connectedProfiles.put(profile, true);
+ }
+ }
+ }
+ }
if (mLastDevice == null && bondedCount == 1) {
mLastDevice = lastBonded;
}
+ // If we are no longer connected to the current device, see if we are connected to
+ // something else, so we don't display a name we aren't connected to.
+ if (mLastDevice != null &&
+ mDeviceInfo.get(mLastDevice).connectionState != BluetoothProfile.STATE_CONNECTED) {
+ // Make sure we don't keep this device while it isn't connected.
+ mLastDevice = null;
+ // Look for anything else connected.
+ final int size = mDeviceInfo.size();
+ for (int i = 0; i < size; i++) {
+ BluetoothDevice device = mDeviceInfo.keyAt(i);
+ DeviceInfo info = mDeviceInfo.valueAt(i);
+ if (info.connectionState == BluetoothProfile.STATE_CONNECTED) {
+ mLastDevice = device;
+ break;
+ }
+ }
+ }
firePairedDevicesChanged();
}
+ private void bindAllProfiles() {
+ // Note: This needs to contain all of the types that can be returned by BluetoothUtil
+ // otherwise we can't find the profiles we need when we connect/disconnect.
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP_SINK);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.AVRCP_CONTROLLER);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET_CLIENT);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.INPUT_DEVICE);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.MAP);
+ mAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.PAN);
+ // Note Health is not in this list because health devices aren't 'connected'.
+ // If profiles are expanded to use more than just connection state and connect/disconnect
+ // then it should be added.
+ }
+
private void firePairedDevicesChanged() {
for (Callback cb : mCallbacks) {
cb.onBluetoothPairedDevicesChanged();
@@ -283,6 +364,20 @@ public class BluetoothControllerImpl implements BluetoothController {
cb.onBluetoothStateChange(mEnabled, mConnecting);
}
+ private final ServiceListener mProfileListener = new ServiceListener() {
+ @Override
+ public void onServiceDisconnected(int profile) {
+ mProfiles.remove(profile);
+ updateBluetoothDevices();
+ }
+
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ mProfiles.put(profile, proxy);
+ updateBluetoothDevices();
+ }
+ };
+
private final class Receiver extends BroadcastReceiver {
public void register() {
final IntentFilter filter = new IntentFilter();
@@ -290,6 +385,15 @@ public class BluetoothControllerImpl implements BluetoothController {
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ALIAS_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_UUID);
+ filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
mContext.registerReceiver(this, filter);
}
@@ -301,16 +405,13 @@ public class BluetoothControllerImpl implements BluetoothController {
setAdapterState(intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, ERROR));
if (DEBUG) Log.d(TAG, "ACTION_STATE_CHANGED " + mEnabled);
} else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
- final DeviceInfo info = updateInfo(device);
+ updateInfo(device);
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
ERROR);
- if (state != ERROR) {
- info.connectionState = state;
- }
mLastDevice = device;
if (DEBUG) Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED "
+ connectionStateToString(state) + " " + deviceToString(device));
- setConnecting(info.connectionState == BluetoothAdapter.STATE_CONNECTING);
+ setConnecting(state == BluetoothAdapter.STATE_CONNECTING);
} else if (action.equals(BluetoothDevice.ACTION_ALIAS_CHANGED)) {
updateInfo(device);
mLastDevice = device;
@@ -318,7 +419,8 @@ public class BluetoothControllerImpl implements BluetoothController {
if (DEBUG) Log.d(TAG, "ACTION_BOND_STATE_CHANGED " + device);
// we'll update all bonded devices below
}
- updateBondedBluetoothDevices();
+ // Always update bluetooth devices state.
+ updateBluetoothDevices();
}
}
@@ -332,5 +434,6 @@ public class BluetoothControllerImpl implements BluetoothController {
private static class DeviceInfo {
int connectionState = BluetoothAdapter.STATE_DISCONNECTED;
boolean bonded; // per getBondedDevices
+ SparseArray<Boolean> connectedProfiles = new SparseArray<>();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java
index 1b4be85..ed8ac2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothUtil.java
@@ -36,7 +36,10 @@ public class BluetoothUtil {
if (profile == BluetoothProfile.HEADSET) return "HEADSET";
if (profile == BluetoothProfile.A2DP) return "A2DP";
if (profile == BluetoothProfile.AVRCP_CONTROLLER) return "AVRCP_CONTROLLER";
- return "UNKNOWN";
+ if (profile == BluetoothProfile.PAN) return "PAN";
+ if (profile == BluetoothProfile.INPUT_DEVICE) return "INPUT_DEVICE";
+ if (profile == BluetoothProfile.MAP) return "MAP";
+ return "UNKNOWN(" + profile + ")";
}
public static String profileStateToString(int state) {
@@ -106,6 +109,11 @@ public class BluetoothUtil {
if (BluetoothUuid.AvrcpController.equals(uuid)) return BluetoothProfile.AVRCP_CONTROLLER;
+ if (BluetoothUuid.Hid.equals(uuid)) return BluetoothProfile.INPUT_DEVICE;
+ if (BluetoothUuid.Hogp.equals(uuid)) return BluetoothProfile.INPUT_DEVICE;
+
+ if (BluetoothUuid.NAP.equals(uuid)) return BluetoothProfile.PAN;
+
return 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index 30da9cb..af51266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -196,6 +196,7 @@ public class MobileDataControllerImpl implements NetworkController.MobileDataCon
}
public void setMobileDataEnabled(boolean enabled) {
+ Log.d(TAG, "setMobileDataEnabled: enabled=" + enabled);
mTelephonyManager.setDataEnabled(enabled);
if (mCallback != null) {
mCallback.onMobileDataEnabled(enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 6431ab5..3397a38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -272,7 +272,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
if (mMobileSignalControllers.containsKey(dataSubId)) {
return mMobileSignalControllers.get(dataSubId);
}
- Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
+ if (DEBUG) Log.e(TAG, "Cannot find controller for data sub: " + dataSubId);
return mDefaultSignalController;
}
@@ -293,7 +293,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
if (mMobileSignalControllers.containsKey(voiceSubId)) {
return mMobileSignalControllers.get(voiceSubId).isEmergencyOnly();
}
- Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
+ if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
// Something is wrong, better assume we can't make calls...
return true;
}
@@ -483,6 +483,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
cachedControllers.get(key).unregisterListener();
}
}
+ // There may be new MobileSignalControllers around, make sure they get the current
+ // inet condition and airplane mode.
+ pushConnectivityToSignals();
+ updateAirplaneMode(true /* force */);
}
private boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
@@ -577,6 +581,13 @@ public class NetworkControllerImpl extends BroadcastReceiver
mBluetoothTethered = mConnectedTransports.get(TRANSPORT_BLUETOOTH);
mEthernetConnected = mConnectedTransports.get(TRANSPORT_ETHERNET);
+ pushConnectivityToSignals();
+ }
+
+ /**
+ * Pushes the current connectivity state to all SignalControllers.
+ */
+ private void pushConnectivityToSignals() {
// We want to update all the icons, all at once, for any condition change
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
mobileSignalController.setInetCondition(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index d3a8fc0..acdcfc1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -124,8 +124,7 @@ public class VolumePanel extends Handler implements DemoMode {
private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13;
private static final int MSG_USER_ACTIVITY = 14;
private static final int MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED = 15;
- private static final int MSG_ZEN_MODE_CHANGED = 16;
- private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 17;
+ private static final int MSG_INTERNAL_RINGER_MODE_CHANGED = 16;
// Pseudo stream type for master volume
private static final int STREAM_MASTER = -100;
@@ -511,6 +510,9 @@ public class VolumePanel extends Handler implements DemoMode {
pw.println();
}
}
+ if (mZenPanel != null) {
+ mZenPanel.dump(fd, pw, args);
+ }
}
private void initZenModePanel() {
@@ -723,7 +725,7 @@ public class VolumePanel extends Handler implements DemoMode {
mSliderPanel.addView(active.group);
mActiveStreamType = activeStreamType;
active.group.setVisibility(View.VISIBLE);
- updateSlider(active);
+ updateSlider(active, true /*forceReloadIcon*/);
updateTimeoutDelay();
updateZenPanelVisible();
}
@@ -799,11 +801,12 @@ public class VolumePanel extends Handler implements DemoMode {
}
/** Update the mute and progress state of a slider */
- private void updateSlider(StreamControl sc) {
+ private void updateSlider(StreamControl sc, boolean forceReloadIcon) {
updateSliderProgress(sc, -1);
final boolean muted = isMuted(sc.streamType);
- // Force reloading the image resource
- sc.icon.setImageDrawable(null);
+ if (forceReloadIcon) {
+ sc.icon.setImageDrawable(null);
+ }
updateSliderIcon(sc, muted);
updateSliderEnabled(sc, muted, false);
updateSliderSuppressor(sc);
@@ -907,11 +910,18 @@ public class VolumePanel extends Handler implements DemoMode {
}
}
- public void updateStates() {
+ private void updateStates() {
final int count = mSliderPanel.getChildCount();
for (int i = 0; i < count; i++) {
StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
- updateSlider(sc);
+ updateSlider(sc, true /*forceReloadIcon*/);
+ }
+ }
+
+ private void updateActiveSlider() {
+ final StreamControl active = mStreamControls.get(mActiveStreamType);
+ if (active != null) {
+ updateSlider(active, false /*forceReloadIcon*/);
}
}
@@ -1449,12 +1459,11 @@ public class VolumePanel extends Handler implements DemoMode {
break;
}
- case MSG_ZEN_MODE_CHANGED:
case MSG_RINGER_MODE_CHANGED:
case MSG_INTERNAL_RINGER_MODE_CHANGED:
case MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED: {
if (isShowing()) {
- updateStates();
+ updateActiveSlider();
}
break;
}
@@ -1563,10 +1572,6 @@ public class VolumePanel extends Handler implements DemoMode {
mNotificationEffectsSuppressor = mZenController.getEffectsSuppressor();
sendEmptyMessage(MSG_NOTIFICATION_EFFECTS_SUPPRESSOR_CHANGED);
}
-
- public void onZenChanged(int zen) {
- sendEmptyMessage(MSG_ZEN_MODE_CHANGED);
- }
};
private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() {
@@ -1591,6 +1596,7 @@ public class VolumePanel extends Handler implements DemoMode {
public void start(StreamControl sc) {
if (sc == null) throw new IllegalArgumentException();
+ if (LOGD) Log.d(mTag, "Secondary icon animation start");
if (mTarget != null) {
cancel();
}
@@ -1643,6 +1649,7 @@ public class VolumePanel extends Handler implements DemoMode {
@Override
public void run() {
if (mTarget == null) return;
+ if (LOGD) Log.d(mTag, "Secondary icon animation complete, show notification slider");
mAudioManager.forceVolumeControlStream(StreamResources.NotificationStream.streamType);
mAudioManager.adjustStreamVolume(StreamResources.NotificationStream.streamType,
AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 6ed24e0..e250ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -17,13 +17,16 @@
package com.android.systemui.volume;
import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
import android.app.ActivityManager;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -32,6 +35,7 @@ import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
@@ -50,6 +54,8 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Objects;
@@ -67,8 +73,7 @@ public class ZenModePanel extends LinearLayout {
private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
private static final int FOREVER_CONDITION_INDEX = 0;
- private static final int TIME_CONDITION_INDEX = 1;
- private static final int FIRST_CONDITION_INDEX = 2;
+ private static final int COUNTDOWN_CONDITION_INDEX = 1;
public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
@@ -81,6 +86,10 @@ public class ZenModePanel extends LinearLayout {
private final int mSubheadColor;
private final Interpolator mInterpolator;
private final int mMaxConditions;
+ private final int mMaxOptionalConditions;
+ private final boolean mCountdownConditionSupported;
+ private final int mFirstConditionIndex;
+ private final TransitionHelper mTransitionHelper = new TransitionHelper();
private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
@@ -98,7 +107,7 @@ public class ZenModePanel extends LinearLayout {
private String mExitConditionText;
private int mBucketIndex = -1;
private boolean mExpanded;
- private boolean mHidden = false;
+ private boolean mHidden;
private int mSessionZen;
private int mAttachedZen;
private boolean mAttached;
@@ -117,11 +126,30 @@ public class ZenModePanel extends LinearLayout {
mSubheadColor = res.getColor(R.color.qs_subhead);
mInterpolator = AnimationUtils.loadInterpolator(mContext,
com.android.internal.R.interpolator.fast_out_slow_in);
+ mCountdownConditionSupported = NotificationManager.from(mContext)
+ .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH);
+ final int countdownDelta = mCountdownConditionSupported ? 1 : 0;
+ mFirstConditionIndex = COUNTDOWN_CONDITION_INDEX + countdownDelta;
+ final int minConditions = 1 /*forever*/ + countdownDelta;
mMaxConditions = MathUtils.constrain(res.getInteger(R.integer.zen_mode_max_conditions),
- 1, 100);
+ minConditions, 100);
+ mMaxOptionalConditions = mMaxConditions - minConditions;
if (DEBUG) Log.d(mTag, "new ZenModePanel");
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("ZenModePanel state:");
+ pw.print(" mCountdownConditionSupported="); pw.println(mCountdownConditionSupported);
+ pw.print(" mMaxConditions="); pw.println(mMaxConditions);
+ pw.print(" mRequestingConditions="); pw.println(mRequestingConditions);
+ pw.print(" mAttached="); pw.println(mAttached);
+ pw.print(" mHidden="); pw.println(mHidden);
+ pw.print(" mExpanded="); pw.println(mExpanded);
+ pw.print(" mSessionZen="); pw.println(mSessionZen);
+ pw.print(" mAttachedZen="); pw.println(mAttachedZen);
+ mTransitionHelper.dump(fd, pw, args);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -135,6 +163,9 @@ public class ZenModePanel extends LinearLayout {
Global.ZEN_MODE_OFF);
mZenButtons.setCallback(mZenButtonsCallback);
+ final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+ zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+
mZenSubhead = findViewById(R.id.zen_subhead);
mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
@@ -159,15 +190,22 @@ public class ZenModePanel extends LinearLayout {
Interaction.register(mMoreSettings, mInteractionCallback);
mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
- setLayoutTransition(newLayoutTransition());
+ for (int i = 0; i < mMaxConditions; i++) {
+ mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
+ }
+
+ setLayoutTransition(newLayoutTransition(mTransitionHelper));
}
- private LayoutTransition newLayoutTransition() {
+ private LayoutTransition newLayoutTransition(TransitionListener listener) {
final LayoutTransition transition = new LayoutTransition();
transition.disableTransitionType(LayoutTransition.DISAPPEARING);
transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
- transition.setInterpolator(LayoutTransition.APPEARING, mInterpolator);
+ transition.disableTransitionType(LayoutTransition.APPEARING);
transition.setInterpolator(LayoutTransition.CHANGE_APPEARING, mInterpolator);
+ if (listener != null) {
+ transition.addTransitionListener(listener);
+ }
return transition;
}
@@ -175,11 +213,11 @@ public class ZenModePanel extends LinearLayout {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (DEBUG) Log.d(mTag, "onAttachedToWindow");
- ((ViewGroup) getParent()).setLayoutTransition(newLayoutTransition());
mAttached = true;
mAttachedZen = getSelectedZen(-1);
mSessionZen = mAttachedZen;
- mSessionExitCondition = copy(mExitCondition);
+ mTransitionHelper.clear();
+ setSessionExitCondition(copy(mExitCondition));
refreshExitConditionText();
updateWidgets();
setRequestingConditions(!mHidden);
@@ -193,9 +231,16 @@ public class ZenModePanel extends LinearLayout {
mAttached = false;
mAttachedZen = -1;
mSessionZen = -1;
- mSessionExitCondition = null;
+ setSessionExitCondition(null);
setExpanded(false);
setRequestingConditions(false);
+ mTransitionHelper.clear();
+ }
+
+ private void setSessionExitCondition(Condition condition) {
+ if (Objects.equals(condition, mSessionExitCondition)) return;
+ if (DEBUG) Log.d(mTag, "mSessionExitCondition=" + getConditionId(condition));
+ mSessionExitCondition = condition;
}
public void setHidden(boolean hidden) {
@@ -228,12 +273,17 @@ public class ZenModePanel extends LinearLayout {
}
/** Start or stop requesting relevant zen mode exit conditions */
- private void setRequestingConditions(boolean requesting) {
+ private void setRequestingConditions(final boolean requesting) {
if (mRequestingConditions == requesting) return;
if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting);
mRequestingConditions = requesting;
if (mController != null) {
- mController.requestConditions(mRequestingConditions);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ mController.requestConditions(requesting);
+ }
+ });
}
if (mRequestingConditions) {
mTimeCondition = parseExistingTimeCondition(mExitCondition);
@@ -248,7 +298,7 @@ public class ZenModePanel extends LinearLayout {
mConditions = null; // reset conditions
handleUpdateConditions();
} else {
- mZenConditions.removeAllViews();
+ hideAllConditions();
}
}
@@ -259,7 +309,7 @@ public class ZenModePanel extends LinearLayout {
mSessionZen = getSelectedZen(-1);
handleUpdateZen(mController.getZen());
if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
- mZenConditions.removeAllViews();
+ hideAllConditions();
mController.addCallback(mZenCallback);
}
@@ -270,6 +320,7 @@ public class ZenModePanel extends LinearLayout {
private void setExitCondition(Condition exitCondition) {
if (Objects.equals(mExitCondition, exitCondition)) return;
mExitCondition = exitCondition;
+ if (DEBUG) Log.d(mTag, "mExitCondition=" + getConditionId(mExitCondition));
refreshExitConditionText();
updateWidgets();
}
@@ -290,7 +341,7 @@ public class ZenModePanel extends LinearLayout {
final String forever = mContext.getString(com.android.internal.R.string.zen_mode_forever);
if (mExitCondition == null) {
mExitConditionText = forever;
- } else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
+ } else if (isCountdown(mExitCondition)) {
final Condition condition = parseExistingTimeCondition(mExitCondition);
mExitConditionText = condition != null ? condition.summary : forever;
} else {
@@ -316,6 +367,24 @@ public class ZenModePanel extends LinearLayout {
}
mZenButtons.setSelectedValue(zen);
updateWidgets();
+ handleUpdateConditions();
+ if (mExpanded) {
+ final Condition selected = getSelectedCondition();
+ if (!Objects.equals(mExitCondition, selected)) {
+ select(selected);
+ }
+ }
+ }
+
+ private Condition getSelectedCondition() {
+ final int N = getVisibleConditions();
+ for (int i = 0; i < N; i++) {
+ final ConditionTag tag = getConditionTagAt(i);
+ if (tag != null && tag.rb.isChecked()) {
+ return tag.condition;
+ }
+ }
+ return null;
}
private int getSelectedZen(int defValue) {
@@ -324,6 +393,10 @@ public class ZenModePanel extends LinearLayout {
}
private void updateWidgets() {
+ if (mTransitionHelper.isTransitioning()) {
+ mTransitionHelper.pendingUpdateWidgets();
+ return;
+ }
final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
final boolean zenOff = zen == Global.ZEN_MODE_OFF;
final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
@@ -371,7 +444,7 @@ public class ZenModePanel extends LinearLayout {
}
private Condition[] trimConditions(Condition[] conditions) {
- if (conditions == null || conditions.length <= mMaxConditions) {
+ if (conditions == null || conditions.length <= mMaxOptionalConditions) {
// no need to trim
return conditions;
}
@@ -384,33 +457,34 @@ public class ZenModePanel extends LinearLayout {
break;
}
}
- final Condition[] rt = Arrays.copyOf(conditions, mMaxConditions);
- if (found >= mMaxConditions) {
+ final Condition[] rt = Arrays.copyOf(conditions, mMaxOptionalConditions);
+ if (found >= mMaxOptionalConditions) {
// found after the first N, promote to the end of the first N
- rt[mMaxConditions - 1] = conditions[found];
+ rt[mMaxOptionalConditions - 1] = conditions[found];
}
return rt;
}
private void handleUpdateConditions() {
+ if (mTransitionHelper.isTransitioning()) {
+ mTransitionHelper.pendingUpdateConditions();
+ return;
+ }
final int conditionCount = mConditions == null ? 0 : mConditions.length;
if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
- for (int i = mZenConditions.getChildCount() - 1; i >= FIRST_CONDITION_INDEX; i--) {
- mZenConditions.removeViewAt(i);
- }
// forever
bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
// countdown
- bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ if (mCountdownConditionSupported) {
+ bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
+ }
// provider conditions
- boolean foundDowntime = false;
for (int i = 0; i < conditionCount; i++) {
- bind(mConditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
- foundDowntime |= isDowntime(mConditions[i]);
+ bind(mConditions[i], mZenConditions.getChildAt(mFirstConditionIndex + i));
}
- // ensure downtime exists, if active
- if (isDowntime(mSessionExitCondition) && !foundDowntime) {
- bind(mSessionExitCondition, null);
+ // hide the rest
+ for (int i = mZenConditions.getChildCount() - 1; i > mFirstConditionIndex + conditionCount; i--) {
+ mZenConditions.getChildAt(i).setVisibility(GONE);
}
// ensure something is selected
if (mExpanded) {
@@ -418,78 +492,101 @@ public class ZenModePanel extends LinearLayout {
}
}
- private static boolean isDowntime(Condition c) {
- return ZenModeConfig.isValidDowntimeConditionId(getConditionId(c));
- }
-
private ConditionTag getConditionTagAt(int index) {
return (ConditionTag) mZenConditions.getChildAt(index).getTag();
}
+ private int getVisibleConditions() {
+ int rt = 0;
+ final int N = mZenConditions.getChildCount();
+ for (int i = 0; i < N; i++) {
+ rt += mZenConditions.getChildAt(i).getVisibility() == VISIBLE ? 1 : 0;
+ }
+ return rt;
+ }
+
+ private void hideAllConditions() {
+ final int N = mZenConditions.getChildCount();
+ for (int i = 0; i < N; i++) {
+ mZenConditions.getChildAt(i).setVisibility(GONE);
+ }
+ }
+
private void ensureSelection() {
// are we left without anything selected? if so, set a default
- if (mZenConditions.getChildCount() == 0) return;
- for (int i = 0; i < mZenConditions.getChildCount(); i++) {
- if (getConditionTagAt(i).rb.isChecked()) {
- if (DEBUG) Log.d(mTag, "Not selecting a default, checked="
- + getConditionTagAt(i).condition);
+ final int visibleConditions = getVisibleConditions();
+ if (visibleConditions == 0) return;
+ for (int i = 0; i < visibleConditions; i++) {
+ final ConditionTag tag = getConditionTagAt(i);
+ if (tag != null && tag.rb.isChecked()) {
+ if (DEBUG) Log.d(mTag, "Not selecting a default, checked=" + tag.condition);
return;
}
}
+ final ConditionTag foreverTag = getConditionTagAt(FOREVER_CONDITION_INDEX);
+ if (foreverTag == null) return;
if (DEBUG) Log.d(mTag, "Selecting a default");
final int favoriteIndex = mPrefs.getMinuteIndex();
- if (favoriteIndex == -1) {
- getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
+ if (favoriteIndex == -1 || !mCountdownConditionSupported) {
+ foreverTag.rb.setChecked(true);
} else {
mTimeCondition = ZenModeConfig.toTimeCondition(mContext,
MINUTE_BUCKETS[favoriteIndex], ActivityManager.getCurrentUser());
mBucketIndex = favoriteIndex;
- bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
- getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
+ bind(mTimeCondition, mZenConditions.getChildAt(COUNTDOWN_CONDITION_INDEX));
+ getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
}
}
private void handleExitConditionChanged(Condition exitCondition) {
setExitCondition(exitCondition);
if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
- final int N = mZenConditions.getChildCount();
+ final int N = getVisibleConditions();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
- tag.rb.setChecked(sameConditionId(tag.condition, mExitCondition));
+ if (tag != null) {
+ if (sameConditionId(tag.condition, mExitCondition)) {
+ bind(exitCondition, mZenConditions.getChildAt(i));
+ }
+ }
}
}
- private void bind(final Condition condition, View convertView) {
+ private boolean isCountdown(Condition c) {
+ return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
+ }
+
+ private void bind(final Condition condition, final View row) {
final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE;
- final View row;
- if (convertView == null) {
- row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
- if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition);
- mZenConditions.addView(row);
- } else {
- row = convertView;
- }
final ConditionTag tag =
row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag();
row.setTag(tag);
+ final boolean first = tag.rb == null;
if (tag.rb == null) {
tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox);
}
tag.condition = condition;
+ final Uri conditionId = getConditionId(tag.condition);
+ if (DEBUG) Log.d(mTag, "bind i=" + mZenConditions.indexOfChild(row) + " first=" + first
+ + " condition=" + conditionId);
tag.rb.setEnabled(enabled);
- if ((mSessionExitCondition != null || mAttachedZen != Global.ZEN_MODE_OFF)
- && sameConditionId(mSessionExitCondition, tag.condition)) {
- tag.rb.setChecked(true);
+ final boolean checked = (mSessionExitCondition != null
+ || mAttachedZen != Global.ZEN_MODE_OFF)
+ && (sameConditionId(mSessionExitCondition, tag.condition)
+ || isCountdown(mSessionExitCondition) && isCountdown(tag.condition));
+ if (checked != tag.rb.isChecked()) {
+ if (DEBUG) Log.d(mTag, "bind checked=" + checked + " condition=" + conditionId);
+ tag.rb.setChecked(checked);
}
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mExpanded && isChecked) {
- if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.condition);
- final int N = mZenConditions.getChildCount();
+ if (DEBUG) Log.d(mTag, "onCheckedChanged " + conditionId);
+ final int N = getVisibleConditions();
for (int i = 0; i < N; i++) {
- ConditionTag childTag = getConditionTagAt(i);
- if (childTag == tag) continue;
+ final ConditionTag childTag = getConditionTagAt(i);
+ if (childTag == null || childTag == tag) continue;
childTag.rb.setChecked(false);
}
select(tag.condition);
@@ -547,8 +644,10 @@ public class ZenModePanel extends LinearLayout {
}
});
- final long time = ZenModeConfig.tryParseCountdownConditionId(getConditionId(tag.condition));
+ final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
if (time > 0) {
+ button1.setVisibility(VISIBLE);
+ button2.setVisibility(VISIBLE);
if (mBucketIndex > -1) {
button1.setEnabled(mBucketIndex > 0);
button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
@@ -563,16 +662,17 @@ public class ZenModePanel extends LinearLayout {
button1.setAlpha(button1.isEnabled() ? 1f : .5f);
button2.setAlpha(button2.isEnabled() ? 1f : .5f);
} else {
- button1.setVisibility(View.GONE);
- button2.setVisibility(View.GONE);
+ button1.setVisibility(GONE);
+ button2.setVisibility(GONE);
}
// wire up interaction callbacks for newly-added condition rows
- if (convertView == null) {
+ if (first) {
Interaction.register(tag.rb, mInteractionCallback);
Interaction.register(tag.lines, mInteractionCallback);
Interaction.register(button1, mInteractionCallback);
Interaction.register(button2, mInteractionCallback);
}
+ row.setVisibility(VISIBLE);
}
private void announceConditionSelection(ConditionTag tag) {
@@ -629,18 +729,23 @@ public class ZenModePanel extends LinearLayout {
announceConditionSelection(tag);
}
- private void select(Condition condition) {
+ private void select(final Condition condition) {
if (DEBUG) Log.d(mTag, "select " + condition);
if (mController != null) {
- mController.setExitCondition(condition);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ mController.setExitCondition(condition);
+ }
+ });
}
setExitCondition(condition);
if (condition == null) {
mPrefs.setMinuteIndex(-1);
- } else if (ZenModeConfig.isValidCountdownConditionId(condition.id) && mBucketIndex != -1) {
+ } else if (isCountdown(condition) && mBucketIndex != -1) {
mPrefs.setMinuteIndex(mBucketIndex);
}
- mSessionExitCondition = copy(condition);
+ setSessionExitCondition(copy(condition));
}
private void fireMoreSettings() {
@@ -784,10 +889,15 @@ public class ZenModePanel extends LinearLayout {
private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
@Override
- public void onSelected(Object value) {
+ public void onSelected(final Object value) {
if (value != null && mZenButtons.isShown()) {
if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
- mController.setZen((Integer) value);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ mController.setZen((Integer) value);
+ }
+ });
}
}
@@ -803,4 +913,79 @@ public class ZenModePanel extends LinearLayout {
fireInteraction();
}
};
+
+ private final class TransitionHelper implements TransitionListener, Runnable {
+ private final ArraySet<View> mTransitioningViews = new ArraySet<View>();
+
+ private boolean mTransitioning;
+ private boolean mPendingUpdateConditions;
+ private boolean mPendingUpdateWidgets;
+
+ public void clear() {
+ mTransitioningViews.clear();
+ mPendingUpdateConditions = mPendingUpdateWidgets = false;
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" TransitionHelper state:");
+ pw.print(" mPendingUpdateConditions="); pw.println(mPendingUpdateConditions);
+ pw.print(" mPendingUpdateWidgets="); pw.println(mPendingUpdateWidgets);
+ pw.print(" mTransitioning="); pw.println(mTransitioning);
+ pw.print(" mTransitioningViews="); pw.println(mTransitioningViews);
+ }
+
+ public void pendingUpdateConditions() {
+ mPendingUpdateConditions = true;
+ }
+
+ public void pendingUpdateWidgets() {
+ mPendingUpdateWidgets = true;
+ }
+
+ public boolean isTransitioning() {
+ return !mTransitioningViews.isEmpty();
+ }
+
+ @Override
+ public void startTransition(LayoutTransition transition,
+ ViewGroup container, View view, int transitionType) {
+ mTransitioningViews.add(view);
+ updateTransitioning();
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition,
+ ViewGroup container, View view, int transitionType) {
+ mTransitioningViews.remove(view);
+ updateTransitioning();
+ }
+
+ @Override
+ public void run() {
+ if (DEBUG) Log.d(mTag, "TransitionHelper run"
+ + " mPendingUpdateWidgets=" + mPendingUpdateWidgets
+ + " mPendingUpdateConditions=" + mPendingUpdateConditions);
+ if (mPendingUpdateWidgets) {
+ updateWidgets();
+ }
+ if (mPendingUpdateConditions) {
+ handleUpdateConditions();
+ }
+ mPendingUpdateWidgets = mPendingUpdateConditions = false;
+ }
+
+ private void updateTransitioning() {
+ final boolean transitioning = isTransitioning();
+ if (mTransitioning == transitioning) return;
+ mTransitioning = transitioning;
+ if (DEBUG) Log.d(mTag, "TransitionHelper mTransitioning=" + mTransitioning);
+ if (!mTransitioning) {
+ if (mPendingUpdateConditions || mPendingUpdateWidgets) {
+ mHandler.post(this);
+ } else {
+ mPendingUpdateConditions = mPendingUpdateWidgets = false;
+ }
+ }
+ }
+ }
}