diff options
Diffstat (limited to 'packages/SystemUI/src')
53 files changed, 794 insertions, 973 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index f184ad2..f5df1a9 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.SystemUIDialog; import java.io.PrintWriter; +import java.text.NumberFormat; public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String TAG = PowerUI.TAG + ".Notification"; @@ -143,7 +144,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { showSaverNotification(); mShowing = SHOWING_SAVER; } else { - mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION); + mNoMan.cancelAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, UserHandle.ALL); mShowing = SHOWING_NOTHING; } } @@ -157,7 +158,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentTitle(mContext.getString(R.string.invalid_charger_title)) .setContentText(mContext.getString(R.string.invalid_charger_text)) .setPriority(Notification.PRIORITY_MAX) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.system_notification_accent_color)); @@ -165,22 +165,22 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (n.headsUpContentView != null) { n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL); } private void showWarningNotification() { final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started : R.string.battery_low_percent_format; + final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0); final Notification.Builder nb = new Notification.Builder(mContext) .setSmallIcon(R.drawable.ic_power_low) // Bump the notification when the bucket dropped. .setWhen(mBucketDroppedNegativeTimeMs) .setShowWhen(false) .setContentTitle(mContext.getString(R.string.battery_low_title)) - .setContentText(mContext.getString(textRes, mBatteryLevel)) + .setContentText(mContext.getString(textRes, percentage)) .setOnlyAlertOnce(true) .setPriority(Notification.PRIORITY_MAX) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.battery_saver_mode_color)); @@ -202,7 +202,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (n.headsUpContentView != null) { n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL); } private void showSaverNotification() { @@ -212,7 +212,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentText(mContext.getString(R.string.battery_saver_notification_text)) .setOngoing(true) .setShowWhen(false) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.battery_saver_mode_color)); @@ -220,7 +219,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (hasSaverSettings()) { nb.setContentIntent(pendingActivity(mOpenSaverSettings)); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.ALL); } private void addStopSaverAction(Notification.Builder nb) { @@ -341,6 +340,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { updateNotification(); } + @Override + public void userSwitched() { + updateNotification(); + } + private void showStartSaverConfirmation() { if (mSaverConfirmation != null) return; final SystemUIDialog d = new SystemUIDialog(mContext); @@ -370,7 +374,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { filter.addAction(ACTION_SHOW_BATTERY_SETTINGS); filter.addAction(ACTION_START_SAVER); filter.addAction(ACTION_STOP_SAVER); - mContext.registerReceiver(this, filter, null, mHandler); + mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index d3c7dee..9459740 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -137,6 +137,7 @@ public class PowerUI extends SystemUI { filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); @@ -207,6 +208,8 @@ public class PowerUI extends SystemUI { mScreenOffTime = SystemClock.elapsedRealtime(); } else if (Intent.ACTION_SCREEN_ON.equals(action)) { mScreenOffTime = -1; + } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { + mWarnings.userSwitched(); } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { updateSaverMode(); } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) { @@ -256,6 +259,7 @@ public class PowerUI extends SystemUI { void updateLowBatteryWarning(); boolean isInvalidChargerWarningShowing(); void dump(PrintWriter pw); + void userSwitched(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java index eb4560d..111484b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java @@ -55,7 +55,6 @@ public class QSDetailClipper { if (listener != null) { mAnimator.addListener(listener); } - mDetail.setLayerType(View.LAYER_TYPE_HARDWARE, null); if (in) { mBackground.startTransition((int)(mAnimator.getDuration() * 0.6)); mAnimator.addListener(mVisibleOnStart); @@ -82,7 +81,6 @@ public class QSDetailClipper { } public void onAnimationEnd(Animator animation) { - mDetail.setLayerType(View.LAYER_TYPE_NONE, null); mAnimator = null; } }; @@ -90,7 +88,6 @@ public class QSDetailClipper { private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mDetail.setLayerType(View.LAYER_TYPE_NONE, null); mDetail.setVisibility(View.GONE); mBackground.resetTransition(); mAnimator = null; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index 3574877..d5c90d0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -132,6 +132,7 @@ public class QSTileView extends ViewGroup { mDualLabel = new QSDualTileLabel(mContext); mDualLabel.setId(android.R.id.title); mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect); + mDualLabel.setFirstLineCaret(res.getDrawable(R.drawable.qs_dual_tile_caret)); mDualLabel.setTextColor(res.getColor(R.color.qs_tile_text)); mDualLabel.setPadding(0, mDualTileVerticalPaddingPx, 0, mDualTileVerticalPaddingPx); mDualLabel.setTypeface(CONDENSED); diff --git a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java index ad79aba..a1092a3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java +++ b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import com.android.systemui.R; import com.android.systemui.statusbar.policy.Listenable; public class UsageTracker implements Listenable { @@ -35,11 +34,10 @@ public class UsageTracker implements Listenable { private boolean mRegistered; - public UsageTracker(Context context, Class<?> tile) { + public UsageTracker(Context context, Class<?> tile, int timeoutResource) { mContext = context; mPrefKey = tile.getSimpleName() + "LastUsed"; - mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources() - .getInteger(R.integer.days_to_show_timeout_tiles); + mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources().getInteger(timeoutResource); mResetAction = "com.android.systemui.qs." + tile.getSimpleName() + ".usage_reset"; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index e99b4c5..84bfb8f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -77,7 +77,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { @Override protected void handleSecondaryClick() { - mHost.startSettingsActivity(BLUETOOTH_SETTINGS); + showDetail(true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 01849c1..7ba1dc0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -44,7 +44,8 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> { } } }; - mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class); + mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class, + R.integer.days_to_show_color_inversion_tile); if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) { mUsageTracker.trackUsage(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index ce99cc3..b30a1d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -34,7 +34,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { public HotspotTile(Host host) { super(host); mController = host.getHotspotController(); - mUsageTracker = new UsageTracker(host.getContext(), HotspotTile.class); + mUsageTracker = newUsageTracker(host.getContext()); mUsageTracker.setListening(true); } @@ -84,6 +84,10 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { } } + private static UsageTracker newUsageTracker(Context context) { + return new UsageTracker(context, HotspotTile.class, R.integer.days_to_show_hotspot_tile); + } + private final class Callback implements HotspotController.Callback { @Override public void onHotspotChanged(boolean enabled) { @@ -101,7 +105,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { @Override public void onReceive(Context context, Intent intent) { if (mUsageTracker == null) { - mUsageTracker = new UsageTracker(context, HotspotTile.class); + mUsageTracker = newUsageTracker(context); } mUsageTracker.trackUsage(); } 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 0985812..20c4ee8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -87,7 +87,15 @@ public class WifiTile extends QSTile<QSTile.SignalState> { @Override protected void handleSecondaryClick() { - mHost.startSettingsActivity(WIFI_SETTINGS); + if (!mController.canConfigWifi()) { + mHost.startSettingsActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); + return; + } + if (!mState.enabled) { + mController.setWifiEnabled(true); + mState.enabled = true; + } + showDetail(true); } @Override @@ -279,7 +287,9 @@ public class WifiTile extends QSTile<QSTile.SignalState> { if (item == null || item.tag == null) return; final AccessPoint ap = (AccessPoint) item.tag; if (!ap.isConnected) { - mController.connect(ap); + if (mController.connect(ap)) { + mHost.collapsePanels(); + } } showDetail(false); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 1283dcd..76e8181 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -54,17 +54,15 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** A proxy implementation for the recents component */ -public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener { +public class AlternateRecentsComponent { 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_APP_FULL_SCREENSHOT = "recents.thumbnail"; 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 ACTION_START_ENTER_ANIMATION = "action_start_enter_animation"; final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity"; final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity"; @@ -74,15 +72,12 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta final static String sRecentsPackage = "com.android.systemui"; final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity"; - static Bitmap sLastScreenshot; static RecentsComponent.Callbacks sRecentsComponentCallbacks; Context mContext; LayoutInflater mInflater; SystemServicesProxy mSystemServicesProxy; - Handler mHandler; boolean mBootCompleted; - boolean mStartAnimationTriggered; // Task launching RecentsConfiguration mConfig; @@ -108,7 +103,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mInflater = LayoutInflater.from(context); mContext = context; mSystemServicesProxy = new SystemServicesProxy(context); - mHandler = new Handler(); mTaskStackBounds = new Rect(); } @@ -132,6 +126,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } } + + // When we start, preload the metadata associated with the previous tasks + RecentsTaskLoader.getInstance().preload(mContext); } public void onBootCompleted() { @@ -256,7 +253,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta public void onConfigurationChanged(Configuration newConfig) { // Reload the header bar layout reloadHeaderBarLayout(); - sLastScreenshot = null; } /** Prepares the header bar layout. */ @@ -330,7 +326,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta // If the user has toggled it too quickly, then just eat up the event here (it's better than // showing a janky screenshot). // NOTE: Ideally, the screenshot mechanism would take the window transform into account - if (System.currentTimeMillis() - mLastToggleTime < sMinToggleDelay) { + long currentTime = System.currentTimeMillis(); + if ((currentTime > mLastToggleTime) && (currentTime - mLastToggleTime) < sMinToggleDelay) { return; } @@ -367,47 +364,30 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta * Creates the activity options for a unknown state->recents transition. */ ActivityOptions getUnknownTransitionActivityOptions() { - mStartAnimationTriggered = false; return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_unknown_enter, - R.anim.recents_from_unknown_exit, mHandler, this); + R.anim.recents_from_unknown_exit); } /** * Creates the activity options for a home->recents transition. */ ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { - mStartAnimationTriggered = false; if (fromSearchHome) { return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_search_launcher_enter, - R.anim.recents_from_search_launcher_exit, mHandler, this); + R.anim.recents_from_search_launcher_exit); } return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_launcher_enter, - R.anim.recents_from_launcher_exit, mHandler, this); + R.anim.recents_from_launcher_exit); } /** - * Creates the activity options for an app->recents transition. If this method sets the static - * screenshot, then we will use that for the transition. + * Creates the activity options for an app->recents transition. */ ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) { - if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { - // Recycle the last screenshot - consumeLastScreenshot(); - - // Take the full screenshot - sLastScreenshot = mSystemServicesProxy.takeAppScreenshot(); - if (sLastScreenshot != null) { - mStartAnimationTriggered = false; - return ActivityOptions.makeCustomAnimation(mContext, - R.anim.recents_from_app_enter, - R.anim.recents_from_app_exit, mHandler, this); - } - } - // Update the destination rect Task toTask = new Task(); TaskViewTransform toTransform = getThumbnailTransitionTransform(topTask.id, isTopTaskHome, @@ -428,10 +408,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta c.setBitmap(null); } - mStartAnimationTriggered = false; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView, thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), - toTaskRect.height(), this); + toTaskRect.height(), null); } // If both the screenshot and thumbnail fails, then just fall back to the default transition @@ -493,11 +472,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta // Try starting with a thumbnail transition ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, isTopTaskHome); if (opts != null) { - if (sLastScreenshot != null) { - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_FULL_SCREENSHOT); - } else { - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL); - } + startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL); } else { // Fall through below to the non-thumbnail transition useThumbnailTransition = false; @@ -535,7 +510,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } else { // Otherwise we do the normal fade from an unknown source ActivityOptions opts = getUnknownTransitionActivityOptions(); - startAlternateRecentsActivity(topTask, opts, null); + startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME); } } mLastToggleTime = System.currentTimeMillis(); @@ -561,19 +536,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } - /** Returns the last screenshot taken, this will be called by the RecentsActivity. */ - public static Bitmap getLastScreenshot() { - return sLastScreenshot; - } - - /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */ - public static void consumeLastScreenshot() { - if (sLastScreenshot != null) { - sLastScreenshot.recycle(); - sLastScreenshot = null; - } - } - /** Sets the RecentsComponent callbacks. */ public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) { sRecentsComponentCallbacks = cb; @@ -585,42 +547,4 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta sRecentsComponentCallbacks.onVisibilityChanged(visible); } } - - /**** OnAnimationStartedListener Implementation ****/ - - @Override - public void onAnimationStarted() { - // Notify recents to start the enter animation - if (!mStartAnimationTriggered) { - // There can be a race condition between the start animation callback and - // the start of the new activity (where we register the receiver that listens - // to this broadcast, so we add our own receiver and if that gets called, then - // we know the activity has not yet started and we can retry sending the broadcast. - BroadcastReceiver fallbackReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() == Activity.RESULT_OK) { - mStartAnimationTriggered = true; - return; - } - - // Schedule for the broadcast to be sent again after some time - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - onAnimationStarted(); - } - }, 75); - } - }; - - // Send the broadcast to notify Recents that the animation has started - Intent intent = new Intent(ACTION_START_ENTER_ANIMATION); - intent.setPackage(mContext.getPackageName()); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, - fallbackReceiver, null, Activity.RESULT_CANCELED, null, null); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 85cf077..9b84d2e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -25,8 +25,6 @@ public class Constants { public static final boolean Verbose = false; public static class App { - // Enables the screenshot app->Recents transition - public static final boolean EnableScreenshotAppTransition = false; // Enables debug drawing for the transition thumbnail public static final boolean EnableTransitionThumbnailDebugMode = false; // Enables the filtering of tasks according to their grouping diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 01ba5a2..d2c55f7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -28,6 +28,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.util.Pair; import android.view.KeyEvent; @@ -102,8 +104,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void run() { // Mark Recents as no longer visible - AlternateRecentsComponent.notifyVisibilityChanged(false); - mVisible = false; + onRecentsActivityVisibilityChanged(false); // Finish Recents if (mLaunchIntent != null) { if (mLaunchOpts != null) { @@ -141,14 +142,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) { // If we are toggling Recents, then first unfilter any filtered stacks first dismissRecentsToFocusedTaskOrHome(true); - } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) { - // Try and start the enter animation (or restart it on configuration changed) - ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null); - mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); - onEnterAnimationTriggered(); - // Notify the fallback receiver that we have successfully got the broadcast - // See AlternateRecentsComponent.onAnimationStarted() - setResultCode(Activity.RESULT_OK); } } }; @@ -163,6 +156,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (action.equals(Intent.ACTION_SCREEN_OFF)) { // When the screen turns off, dismiss Recents to Home dismissRecentsToHome(false); + // Start preloading some tasks in the background + RecentsTaskLoader.getInstance().preload(RecentsActivity.this); } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) { // When the search activity changes, update the Search widget refreshSearchWidget(); @@ -189,8 +184,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView AlternateRecentsComponent.EXTRA_FROM_HOME, false); mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra( AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false); - mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false); mConfig.launchedToTaskId = launchIntent.getIntExtra( AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1); mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( @@ -435,6 +428,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } + /** Called when the configuration changes. */ void onConfigurationChange() { // Update RecentsConfiguration mConfig = RecentsConfiguration.reinitialize(this, @@ -443,7 +437,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Try and start the enter animation (or restart it on configuration changed) ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); - onEnterAnimationTriggered(); + // Animate the SystemUI scrim views + mScrimViews.startEnterRecentsAnimation(); + } + + /** Handles changes to the activity visibility. */ + void onRecentsActivityVisibilityChanged(boolean visible) { + if (!visible) { + AlternateRecentsComponent.notifyVisibilityChanged(visible); + } + mVisible = visible; } @Override @@ -471,7 +474,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView IntentFilter filter = new IntentFilter(); filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY); filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY); - filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION); registerReceiver(mServiceBroadcastReceiver, filter); // Register any broadcast receivers for the task loader @@ -483,7 +485,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView super.onResume(); // Mark Recents as visible - mVisible = true; + onRecentsActivityVisibilityChanged(true); } @Override @@ -514,6 +516,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } @Override + public void onEnterAnimationComplete() { + // Try and start the enter animation (or restart it on configuration changed) + ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); + mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); + + // Animate the SystemUI scrim views + mScrimViews.startEnterRecentsAnimation(); + } + + @Override public void onTrimMemory(int level) { RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); if (loader != null) { @@ -594,12 +606,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } - /** Called when the enter recents animation is triggered. */ - public void onEnterAnimationTriggered() { - // Animate the SystemUI scrim views - mScrimViews.startEnterRecentsAnimation(); - } - /**** RecentsView.RecentsViewCallbacks Implementation ****/ @Override @@ -611,8 +617,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onTaskViewClicked() { // Mark recents as no longer visible - AlternateRecentsComponent.notifyVisibilityChanged(false); - mVisible = false; + 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 2aca576..bfea3f7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -307,7 +307,6 @@ public class RecentsConfiguration { launchedWithAltTab = false; launchedWithNoRecentTasks = false; launchedFromAppWithThumbnail = false; - launchedFromAppWithScreenshot = false; launchedFromHome = false; launchedToTaskId = -1; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index f01d17c..a0dee07 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -16,6 +16,7 @@ package com.android.systemui.recents.misc; +import android.animation.Animator; import android.content.Intent; import android.graphics.Color; import android.graphics.Matrix; @@ -188,4 +189,15 @@ public class Utilities { int flags = intent.getFlags(); return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT; } + + /** + * Cancels an animation ensuring that if it has listeners, onCancel and onEnd + * are not called. + */ + public static void cancelAnimationWithoutCallbacks(Animator animator) { + if (animator != null) { + animator.removeAllListeners(); + animator.cancel(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java index 7ccefc6..97e0916 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java @@ -21,15 +21,16 @@ import android.util.LruCache; import java.util.HashMap; /** - * An LRU cache that support querying the keys as well as values. By using the Task's key, we can - * prevent holding onto a reference to the Task resource data, while keeping the cache data in - * memory where necessary. + * An LRU cache that internally support querying the keys as well as values. We use this to keep + * track of the task metadata to determine when to invalidate the cache when tasks have been + * updated. Generally, this cache will return the last known cache value for the requested task + * key. */ public class KeyStoreLruCache<V> { // We keep a set of keys that are associated with the LRU cache, so that we can find out // information about the Task that was previously in the cache. HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>(); - // The cache implementation + // The cache implementation, mapping task id -> value LruCache<Integer, V> mCache; public KeyStoreLruCache(int cacheSize) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java index 60e89bf..e48e5f0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java @@ -19,6 +19,7 @@ package com.android.systemui.recents.model; import android.content.ComponentName; import android.content.Context; import android.os.Looper; +import android.os.UserHandle; import com.android.internal.content.PackageMonitor; import com.android.systemui.recents.misc.SystemServicesProxy; @@ -26,16 +27,16 @@ import java.util.HashSet; import java.util.List; /** - * The package monitor listens for changes from PackageManager to update the contents of the Recents - * list. + * The package monitor listens for changes from PackageManager to update the contents of the + * Recents list. */ public class RecentsPackageMonitor extends PackageMonitor { public interface PackageCallbacks { - public void onComponentRemoved(HashSet<ComponentName> cns); + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, + int userId); } PackageCallbacks mCb; - List<Task.TaskKey> mTasks; SystemServicesProxy mSystemServicesProxy; /** Registers the broadcast receivers with the specified callbacks. */ @@ -43,7 +44,9 @@ public class RecentsPackageMonitor extends PackageMonitor { mSystemServicesProxy = new SystemServicesProxy(context); mCb = cb; try { - register(context, Looper.getMainLooper(), true); + // We register for events from all users, but will cross-reference them with + // packages for the current user and any profiles they have + register(context, Looper.getMainLooper(), UserHandle.ALL, true); } catch (IllegalStateException e) { e.printStackTrace(); } @@ -59,29 +62,15 @@ public class RecentsPackageMonitor extends PackageMonitor { } mSystemServicesProxy = null; mCb = null; - mTasks.clear(); - } - - /** Sets the list of tasks to match against package broadcast changes. */ - void setTasks(List<Task.TaskKey> tasks) { - mTasks = tasks; } @Override public void onPackageRemoved(String packageName, int uid) { if (mCb == null) return; - // Identify all the tasks that should be removed as a result of the package being removed. - // Using a set to ensure that we callback once per unique component. - HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); - for (Task.TaskKey t : mTasks) { - ComponentName cn = t.baseIntent.getComponent(); - if (cn.getPackageName().equals(packageName)) { - componentsToRemove.add(cn); - } - } - // Notify our callbacks that the components no longer exist - mCb.onComponentRemoved(componentsToRemove); + // Notify callbacks that a package has changed + final int eventUserId = getChangingUserId(); + mCb.onPackagesChanged(this, packageName, eventUserId); } @Override @@ -94,25 +83,38 @@ public class RecentsPackageMonitor extends PackageMonitor { public void onPackageModified(String packageName) { if (mCb == null) return; + // Notify callbacks that a package has changed + final int eventUserId = getChangingUserId(); + mCb.onPackagesChanged(this, packageName, eventUserId); + } + + /** + * Computes the components that have been removed as a result of a change in the specified + * package. + */ + public HashSet<ComponentName> computeComponentsRemoved(List<Task.TaskKey> taskKeys, + String packageName, int userId) { // Identify all the tasks that should be removed as a result of the package being removed. // Using a set to ensure that we callback once per unique component. - HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>(); - HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); - for (Task.TaskKey t : mTasks) { + HashSet<ComponentName> existingComponents = new HashSet<ComponentName>(); + HashSet<ComponentName> removedComponents = new HashSet<ComponentName>(); + for (Task.TaskKey t : taskKeys) { + // Skip if this doesn't apply to the current user + if (t.userId != userId) continue; + ComponentName cn = t.baseIntent.getComponent(); if (cn.getPackageName().equals(packageName)) { - if (componentsKnownToExist.contains(cn)) { + if (existingComponents.contains(cn)) { // If we know that the component still exists in the package, then skip continue; } - if (mSystemServicesProxy.getActivityInfo(cn) != null) { - componentsKnownToExist.add(cn); + if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) { + existingComponents.add(cn); } else { - componentsToRemove.add(cn); + removedComponents.add(cn); } } } - // Notify our callbacks that the components no longer exist - mCb.onComponentRemoved(componentsToRemove); + return removedComponents; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index d40e847..b4f62d5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -171,6 +171,9 @@ class TaskResourceLoader implements Runnable { } } else { SystemServicesProxy ssp = mSystemServicesProxy; + // If we've stopped the loader, then fall thorugh to the above logic to wait on + // the load thread + if (ssp == null) continue; // Load the next item from the queue final Task t = mLoadQueue.nextTask(); @@ -418,17 +421,25 @@ public class RecentsTaskLoader { root.setStack(stack); // Start the task loader and add all the tasks we need to load - mLoader.start(context); mLoadQueue.addTasks(tasksToLoad); - - // Update the package monitor with the list of packages to listen for - mPackageMonitor.setTasks(taskKeys); + mLoader.start(context); return root; } + /** Preloads the set of recent tasks (not including thumbnails). */ + public void preload(Context context) { + ArrayList<Task> tasksToLoad = new ArrayList<Task>(); + getTaskStack(mSystemServicesProxy, context.getResources(), + -1, -1, true, true, null, tasksToLoad); + + // Start the task loader and add all the tasks we need to load + mLoadQueue.addTasks(tasksToLoad); + mLoader.start(context); + } + /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */ - public TaskStack getTaskStack(SystemServicesProxy ssp, Resources res, + public synchronized TaskStack getTaskStack(SystemServicesProxy ssp, Resources res, int preloadTaskId, int preloadTaskCount, boolean loadTaskThumbnails, boolean isTopTaskHome, List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index a7e2b0b..55dfe45 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -129,7 +129,7 @@ public class Task { TaskCallbacks mCb; public Task() { - // Only used by RecentsService for task rect calculations. + // Do nothing } public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor, diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 1e47b50..a37b9e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -255,6 +255,17 @@ public class TaskStack { return mTaskList.getTasks().get(mTaskList.size() - 1); } + /** Gets the task keys */ + public ArrayList<Task.TaskKey> getTaskKeys() { + ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>(); + ArrayList<Task> tasks = mTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + taskKeys.add(tasks.get(i).key); + } + return taskKeys; + } + /** Gets the tasks */ public ArrayList<Task> getTasks() { return mTaskList.getTasks(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java index d2fdaff..5f8f3f2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -17,12 +17,10 @@ package com.android.systemui.recents.views; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.graphics.Outline; import android.graphics.Rect; import android.view.View; import android.view.ViewOutlineProvider; - import com.android.systemui.recents.RecentsConfiguration; /* An outline provider that has a clip and outline that can be animated. */ @@ -31,35 +29,27 @@ public class AnimateableViewBounds extends ViewOutlineProvider { RecentsConfiguration mConfig; TaskView mSourceView; - Rect mTmpRect = new Rect(); Rect mClipRect = new Rect(); Rect mClipBounds = new Rect(); - Rect mOutlineClipRect = new Rect(); int mCornerRadius; float mAlpha = 1f; final float mMinAlpha = 0.25f; - ObjectAnimator mClipTopAnimator; - ObjectAnimator mClipRightAnimator; ObjectAnimator mClipBottomAnimator; public AnimateableViewBounds(TaskView source, int cornerRadius) { mConfig = RecentsConfiguration.getInstance(); mSourceView = source; mCornerRadius = cornerRadius; - setClipTop(getClipTop()); - setClipRight(getClipRight()); setClipBottom(getClipBottom()); - setOutlineClipBottom(getOutlineClipBottom()); } @Override public void getOutline(View view, Outline outline) { outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha)); - outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left), - Math.max(mClipRect.top, mOutlineClipRect.top), - mSourceView.getWidth() - Math.max(mClipRect.right, mOutlineClipRect.right), - mSourceView.getHeight() - Math.max(mClipRect.bottom, mOutlineClipRect.bottom), + outline.setRoundRect(mClipRect.left, mClipRect.top, + mSourceView.getWidth() - mClipRect.right, + mSourceView.getHeight() - mClipRect.bottom, mCornerRadius); } @@ -71,73 +61,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider { } } - /** Animates the top clip. */ - void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) { - if (mClipTopAnimator != null) { - mClipTopAnimator.removeAllListeners(); - mClipTopAnimator.cancel(); - } - mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top); - mClipTopAnimator.setDuration(duration); - mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - if (updateListener != null) { - mClipTopAnimator.addUpdateListener(updateListener); - } - mClipTopAnimator.start(); - } - - /** Sets the top clip. */ - public void setClipTop(int top) { - if (top != mClipRect.top) { - mClipRect.top = top; - mSourceView.invalidateOutline(); - updateClipBounds(); - } - } - - /** Returns the top clip. */ - public int getClipTop() { - return mClipRect.top; - } - - /** Animates the right clip. */ - void animateClipRight(int right, int duration) { - if (mClipRightAnimator != null) { - mClipRightAnimator.removeAllListeners(); - mClipRightAnimator.cancel(); - } - mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right); - mClipRightAnimator.setDuration(duration); - mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mClipRightAnimator.start(); - } - - /** Sets the right clip. */ - public void setClipRight(int right) { - if (right != mClipRect.right) { - mClipRect.right = right; - mSourceView.invalidateOutline(); - updateClipBounds(); - } - } - - /** Returns the right clip. */ - public int getClipRight() { - return mClipRect.right; - } - - /** Animates the bottom clip. */ - void animateClipBottom(int bottom, int duration) { - if (mClipBottomAnimator != null) { - mClipBottomAnimator.removeAllListeners(); - mClipBottomAnimator.cancel(); - } - mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom); - mClipBottomAnimator.setDuration(duration); - mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mClipBottomAnimator.start(); - } - /** Sets the bottom clip. */ public void setClipBottom(int bottom) { if (bottom != mClipRect.bottom) { @@ -145,7 +68,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mSourceView.invalidateOutline(); updateClipBounds(); if (!mConfig.useHardwareLayers) { - mSourceView.mThumbnailView.updateVisibility( + mSourceView.mThumbnailView.updateThumbnailVisibility( bottom - mSourceView.getPaddingBottom()); } } @@ -156,19 +79,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider { return mClipRect.bottom; } - /** Sets the outline bottom clip. */ - public void setOutlineClipBottom(int bottom) { - if (bottom != mOutlineClipRect.bottom) { - mOutlineClipRect.bottom = bottom; - mSourceView.invalidateOutline(); - } - } - - /** Gets the outline bottom clip. */ - public int getOutlineClipBottom() { - return mOutlineClipRect.bottom; - } - private void updateClipBounds() { mClipBounds.set(mClipRect.left, mClipRect.top, mSourceView.getWidth() - mClipRect.right, 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 6c22a3b..6b0d306 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -18,8 +18,6 @@ package com.android.systemui.recents.views; import android.app.ActivityOptions; import android.app.TaskStackBuilder; -import android.content.ActivityNotFoundException; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -35,7 +33,6 @@ import android.view.WindowInsets; import android.widget.FrameLayout; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.misc.Console; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.RecentsPackageMonitor; @@ -44,7 +41,6 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; -import java.util.HashSet; /** * This view is the the top level layout that contains TaskStacks (which are laid out according @@ -339,7 +335,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV View child = getChildAt(i); if (child != mSearchBar) { TaskStackView stackView = (TaskStackView) child; - stackView.focusNextTask(forward); + stackView.focusNextTask(forward, true); break; } } @@ -566,14 +562,14 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override - public void onComponentRemoved(HashSet<ComponentName> cns) { + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { // Propagate this event down to each task stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child != mSearchBar) { TaskStackView stackView = (TaskStackView) child; - stackView.onComponentRemoved(cns); + stackView.onPackagesChanged(monitor, packageName, userId); } } } 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 40134da..dee26e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -24,7 +24,6 @@ import android.graphics.Rect; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import com.android.systemui.R; @@ -415,7 +414,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** Focuses the task at the specified index in the stack */ - void focusTask(int taskIndex, boolean scrollToNewPosition) { + void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) { // Return early if the task is already focused if (taskIndex == mFocusedTaskIndex) return; @@ -427,7 +426,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView tv = getChildViewForTask(t); Runnable postScrollRunnable = null; if (tv != null) { - tv.setFocusedTask(); + tv.setFocusedTask(animateFocusedState); } else { postScrollRunnable = new Runnable() { @Override @@ -435,7 +434,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task t = mStack.getTasks().get(mFocusedTaskIndex); TaskView tv = getChildViewForTask(t); if (tv != null) { - tv.setFocusedTask(); + tv.setFocusedTask(animateFocusedState); } } }; @@ -455,18 +454,50 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - /** Focuses the next task in the stack */ - void focusNextTask(boolean forward) { + /** + * Ensures that there is a task focused, if nothign is focused, then we will use the task + * at the center of the visible stack. + */ + public boolean ensureFocusedTask() { + if (mFocusedTaskIndex < 0) { + // If there is no task focused, then find the task that is closes to the center + // of the screen and use that as the currently focused task + int x = mLayoutAlgorithm.mStackVisibleRect.centerX(); + int y = mLayoutAlgorithm.mStackVisibleRect.centerY(); + int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + TaskView tv = (TaskView) getChildAt(i); + tv.getHitRect(mTmpRect); + if (mTmpRect.contains(x, y)) { + mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); + break; + } + } + // If we can't find the center task, then use the front most index + if (mFocusedTaskIndex < 0 && childCount > 0) { + mFocusedTaskIndex = childCount - 1; + } + } + return mFocusedTaskIndex >= 0; + } + + /** + * Focuses the next task in the stack. + * @param animateFocusedState determines whether to actually draw the highlight along with + * the change in focus, as well as whether to scroll to fit the + * task into view. + */ + public void focusNextTask(boolean forward, boolean animateFocusedState) { // Find the next index to focus int numTasks = mStack.getTaskCount(); if (numTasks == 0) return; - int nextFocusIndex = numTasks - 1; - if (0 <= mFocusedTaskIndex && mFocusedTaskIndex < numTasks) { - nextFocusIndex = Math.max(0, Math.min(numTasks - 1, - mFocusedTaskIndex + (forward ? -1 : 1))); + int direction = (forward ? -1 : 1); + int newIndex = mFocusedTaskIndex + direction; + if (newIndex >= 0 && newIndex <= (numTasks - 1)) { + newIndex = Math.max(0, Math.min(numTasks - 1, newIndex)); + focusTask(newIndex, true, animateFocusedState); } - focusTask(nextFocusIndex, true); } /** Dismisses the focused task. */ @@ -506,6 +537,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override + public boolean onGenericMotionEvent(MotionEvent ev) { + return mTouchHandler.onGenericMotionEvent(ev); + } + + @Override public void computeScroll() { mStackScroller.computeScroll(); // Synchronize the views @@ -562,22 +598,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); - if (tv.isFullScreenView()) { - tv.measure(widthMeasureSpec, heightMeasureSpec); + if (tv.getBackground() != null) { + tv.getBackground().getPadding(mTmpRect); } else { - if (tv.getBackground() != null) { - tv.getBackground().getPadding(mTmpRect); - } else { - mTmpRect.setEmpty(); - } - tv.measure( - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, - MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom + - tv.getMaxFooterHeight(), MeasureSpec.EXACTLY)); + mTmpRect.setEmpty(); } + tv.measure( + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom, + MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); @@ -594,20 +626,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); - if (tv.isFullScreenView()) { - tv.layout(left, top, left + tv.getMeasuredWidth(), top + tv.getMeasuredHeight()); + if (tv.getBackground() != null) { + tv.getBackground().getPadding(mTmpRect); } else { - if (tv.getBackground() != null) { - tv.getBackground().getPadding(mTmpRect); - } else { - mTmpRect.setEmpty(); - } - tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left, - mLayoutAlgorithm.mTaskRect.top - mTmpRect.top, - mLayoutAlgorithm.mTaskRect.right + mTmpRect.right, - mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom + - tv.getMaxFooterHeight()); + mTmpRect.setEmpty(); } + tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left, + mLayoutAlgorithm.mTaskRect.top - mTmpRect.top, + mLayoutAlgorithm.mTaskRect.right + mTmpRect.right, + mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom); } if (mAwaitingFirstLayout) { @@ -653,9 +680,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // When Alt-Tabbing, we scroll to and focus the previous task if (mConfig.launchedWithAltTab) { if (mConfig.launchedFromHome) { - focusTask(Math.max(0, mStack.getTaskCount() - 1), false); + focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true); } else { - focusTask(Math.max(0, mStack.getTaskCount() - 2), false); + focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true); } } } @@ -811,6 +838,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView frontTv = getChildViewForTask(newFrontMostTask); if (frontTv != null) { frontTv.onTaskBound(newFrontMostTask); + frontTv.fadeInActionButton(false); } } @@ -923,13 +951,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Rebind the task and request that this task's data be filled into the TaskView tv.onTaskBound(task); - // Mark the launch task as fullscreen - if (Constants.DebugFlags.App.EnableScreenshotAppTransition && mAwaitingFirstLayout) { - if (task.isLaunchTarget) { - tv.setIsFullScreen(true); - } - } - // Load the task data RecentsTaskLoader.getInstance().loadTaskData(task); @@ -1018,14 +1039,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal tv.getTask().activityLabel)); // Remove the task from the view mStack.removeTask(task); - // If the dismissed task was focused, then we should focus the next task in front + // If the dismissed task was focused, then we should focus the new task in the same index if (taskWasFocused) { ArrayList<Task> tasks = mStack.getTasks(); - int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex); + int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1); if (nextTaskIndex >= 0) { Task nextTask = tasks.get(nextTaskIndex); TaskView nextTv = getChildViewForTask(nextTask); - nextTv.setFocusedTask(); + if (nextTv != null) { + // Focus the next task, and only animate the visible state if we are launched + // from Alt-Tab + nextTv.setFocusedTask(mConfig.launchedWithAltTab); + } } } } @@ -1038,11 +1063,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override - public void onTaskViewFullScreenTransitionCompleted() { - requestSynchronizeStackViewsWithModel(); - } - - @Override public void onTaskViewFocusChanged(TaskView tv, boolean focused) { if (focused) { mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); @@ -1061,12 +1081,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override - public void onComponentRemoved(HashSet<ComponentName> cns) { + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { + // Compute which components need to be removed + HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved( + mStack.getTaskKeys(), packageName, userId); + // For other tasks, just remove them directly if they no longer exist ArrayList<Task> tasks = mStack.getTasks(); for (int i = tasks.size() - 1; i >= 0; i--) { final Task t = tasks.get(i); - if (cns.contains(t.key.baseIntent.getComponent())) { + if (removedComponents.contains(t.key.baseIntent.getComponent())) { TaskView tv = getChildViewForTask(t); if (tv != null) { // For visible children, defer removing the task until after the animation 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 31fc701..c549d2b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -199,18 +199,14 @@ public class TaskStackViewLayoutAlgorithm { return transformOut; } - /** - * Returns the untransformed task view size. - */ + /** Returns the untransformed task view size. */ public Rect getUntransformedTaskViewSize() { Rect tvSize = new Rect(mTaskRect); tvSize.offsetTo(0, 0); return tvSize; } - /** - * Returns the scroll to such task top = 1f; - */ + /** Returns the scroll to such task top = 1f; */ float getStackScrollForTask(Task t) { return mTaskProgressMap.get(t.key); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index 5852b88..04f7c6f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -23,6 +23,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.widget.OverScroller; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.misc.Utilities; /* The scrolling logic for a TaskStackView */ public class TaskStackViewScroller { @@ -38,6 +39,7 @@ public class TaskStackViewScroller { OverScroller mScroller; ObjectAnimator mScrollAnimator; + float mFinalAnimatedScroll; public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) { mConfig = config; @@ -128,10 +130,15 @@ public class TaskStackViewScroller { /** Animates the stack scroll */ void animateScroll(float curScroll, float newScroll, final Runnable postRunnable) { - // Abort any current animations + // Finish any current scrolling animations + if (mScrollAnimator != null && mScrollAnimator.isRunning()) { + setStackScroll(mFinalAnimatedScroll); + mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0); + } stopScroller(); stopBoundScrollAnimation(); + mFinalAnimatedScroll = newScroll; mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll); mScrollAnimator.setDuration(mConfig.taskStackScrollDuration); mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator); @@ -155,10 +162,7 @@ public class TaskStackViewScroller { /** Aborts any current stack scrolls */ void stopBoundScrollAnimation() { - if (mScrollAnimator != null) { - mScrollAnimator.removeAllListeners(); - mScrollAnimator.cancel(); - } + Utilities.cancelAnimationWithoutCallbacks(mScrollAnimator); } /**** OverScroller ****/ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index 8f9b4c2..2b173a9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -17,6 +17,7 @@ package com.android.systemui.recents.views; import android.content.Context; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -189,7 +190,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { /** Handles touch events once we have intercepted them */ public boolean onTouchEvent(MotionEvent ev) { - // Short circuit if we have no children boolean hasChildren = (mSv.getChildCount() > 0); if (!hasChildren) { @@ -336,6 +336,30 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { return true; } + /** Handles generic motion events */ + public boolean onGenericMotionEvent(MotionEvent ev) { + if ((ev.getSource() & InputDevice.SOURCE_CLASS_POINTER) == + InputDevice.SOURCE_CLASS_POINTER) { + int action = ev.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_SCROLL: + // Find the front most task and scroll the next task to the front + float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL); + if (vScroll > 0) { + if (mSv.ensureFocusedTask()) { + mSv.focusNextTask(true, false); + } + } else { + if (mSv.ensureFocusedTask()) { + mSv.focusNextTask(false, false); + } + } + return true; + } + } + return false; + } + /**** SwipeHelper Implementation ****/ @Override @@ -355,8 +379,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { tv.setClipViewInStack(false); // Disallow touch events from this task view tv.setTouchEnabled(false); - // Hide the footer - tv.animateFooterVisibility(false, mSv.mConfig.taskViewLockToAppShortAnimDuration); // Disallow parents from intercepting touch events final ViewParent parent = mSv.getParent(); if (parent != null) { @@ -387,8 +409,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { tv.setClipViewInStack(true); // Re-enable touch events from this task view tv.setTouchEnabled(true); - // Restore the footer - tv.animateFooterVisibility(true, mSv.mConfig.taskViewLockToAppShortAnimDuration); } @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 2658176..7b4e10a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -21,23 +21,22 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.*; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.ViewPropertyAnimator; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.recents.AlternateRecentsComponent; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.model.RecentsTaskLoader; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; +import com.android.systemui.statusbar.phone.PhoneStatusBar; /* A task view */ public class TaskView extends FrameLayout implements Task.TaskCallbacks, - TaskViewFooter.TaskFooterViewCallbacks, View.OnClickListener, View.OnLongClickListener { + View.OnClickListener, View.OnLongClickListener { /** The TaskView callbacks */ interface TaskViewCallbacks { @@ -46,7 +45,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask); public void onTaskViewDismissed(TaskView tv); public void onTaskViewClipStateChanged(TaskView tv); - public void onTaskViewFullScreenTransitionCompleted(); public void onTaskViewFocusChanged(TaskView tv, boolean focused); } @@ -54,25 +52,22 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, float mTaskProgress; ObjectAnimator mTaskProgressAnimator; - ObjectAnimator mDimAnimator; float mMaxDimScale; - int mDim; + int mDimAlpha; AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1f); - PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.MULTIPLY); + PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); + Paint mDimLayerPaint = new Paint(); Task mTask; boolean mTaskDataLoaded; boolean mIsFocused; boolean mFocusAnimationsEnabled; - boolean mIsFullScreenView; boolean mClipViewInStack; AnimateableViewBounds mViewBounds; - Paint mLayerPaint = new Paint(); View mContent; TaskViewThumbnail mThumbnailView; TaskViewHeader mHeaderView; - TaskViewFooter mFooterView; View mActionButtonView; TaskViewCallbacks mCb; @@ -133,7 +128,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mContent = findViewById(R.id.task_view_content); mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar); mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail); - mThumbnailView.enableTaskBarClip(mHeaderView); + mThumbnailView.updateClipToTaskBar(mHeaderView); mActionButtonView = findViewById(R.id.lock_to_app_fab); mActionButtonView.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -142,9 +137,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight()); } }); - if (mFooterView != null) { - mFooterView.setCallbacks(this); - } } @Override @@ -159,29 +151,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); - // Measure the bar view, thumbnail, and footer + // Measure the bar view, and action button mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY)); - if (mFooterView != null) { - mFooterView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mConfig.taskViewLockToAppButtonHeight, - MeasureSpec.EXACTLY)); - } mActionButtonView.measure( MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST)); - if (mIsFullScreenView) { - // Measure the thumbnail height to be the full dimensions - mThumbnailView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY)); - } else { - // Measure the thumbnail to be square - mThumbnailView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); - } + // Measure the thumbnail to be square + mThumbnailView.measure( + MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); setMeasuredDimension(width, height); invalidateOutline(); } @@ -193,25 +172,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration, ValueAnimator.AnimatorUpdateListener updateCallback) { - // If we are a full screen view, then only update the Z to keep it in order - // XXX: Also update/animate the dim as well - if (mIsFullScreenView) { - if (!mConfig.fakeShadows && - toTransform.hasTranslationZChangedFrom(getTranslationZ())) { - setTranslationZ(toTransform.translationZ); - } - return; - } - // Apply the transform toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false, !mConfig.fakeShadows, updateCallback); // Update the task progress - if (mTaskProgressAnimator != null) { - mTaskProgressAnimator.removeAllListeners(); - mTaskProgressAnimator.cancel(); - } + Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator); if (duration <= 0) { setTaskProgress(toTransform.p); } else { @@ -253,22 +219,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean occludesLaunchTarget, int offscreenY) { int initialDim = getDim(); - if (mConfig.launchedFromAppWithScreenshot) { + if (mConfig.launchedFromAppWithThumbnail) { if (isTaskViewLaunchTargetTask) { - // Hide the footer during the transition in, and animate it out afterwards? - if (mFooterView != null) { - mFooterView.animateFooterVisibility(false, 0); - } - } else { - // Don't do anything for the side views when animating in - } - - } else if (mConfig.launchedFromAppWithThumbnail) { - if (isTaskViewLaunchTargetTask) { - // Hide the action button if it exists - mActionButtonView.setAlpha(0f); // Set the dim to 0 so we can animate it in initialDim = 0; + // Hide the action button + mActionButtonView.setAlpha(0f); } else if (occludesLaunchTarget) { // Move the task view off screen (below) so we can animate it in setTranslationY(offscreenY); @@ -292,74 +248,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, final TaskViewTransform transform = ctx.currentTaskTransform; int startDelay = 0; - if (mConfig.launchedFromAppWithScreenshot) { - if (mTask.isLaunchTarget) { - Rect taskRect = ctx.currentTaskRect; - int duration = mConfig.taskViewEnterFromHomeDuration * 10; - int windowInsetTop = mConfig.systemInsets.top; // XXX: Should be for the window - float taskScale = ((float) taskRect.width() / getMeasuredWidth()) * transform.scale; - float scaledYOffset = ((1f - taskScale) * getMeasuredHeight()) / 2; - float scaledWindowInsetTop = (int) (taskScale * windowInsetTop); - float scaledTranslationY = taskRect.top + transform.translationY - - (scaledWindowInsetTop + scaledYOffset); - startDelay = mConfig.taskViewEnterFromHomeStaggerDelay; - - // Animate the top clip - mViewBounds.animateClipTop(windowInsetTop, duration, - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int y = (Integer) animation.getAnimatedValue(); - mHeaderView.setTranslationY(y); - } - }); - // Animate the bottom or right clip - int size = Math.round((taskRect.width() / taskScale)); - if (mConfig.hasHorizontalLayout()) { - mViewBounds.animateClipRight(getMeasuredWidth() - size, duration); - } else { - mViewBounds.animateClipBottom(getMeasuredHeight() - (windowInsetTop + size), duration); - } - // Animate the task bar of the first task view - animate() - .scaleX(taskScale) - .scaleY(taskScale) - .translationY(scaledTranslationY) - .setDuration(duration) - .withEndAction(new Runnable() { - @Override - public void run() { - setIsFullScreen(false); - requestLayout(); - - // Reset the clip - mViewBounds.setClipTop(0); - mViewBounds.setClipBottom(0); - mViewBounds.setClipRight(0); - // Reset the bar translation - mHeaderView.setTranslationY(0); - // Animate the footer into view (if it is the front most task) - animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration); - - // Unbind the thumbnail from the screenshot - RecentsTaskLoader.getInstance().loadTaskData(mTask); - // Recycle the full screen screenshot - AlternateRecentsComponent.consumeLastScreenshot(); - - mCb.onTaskViewFullScreenTransitionCompleted(); - - // Decrement the post animation trigger - ctx.postAnimationTrigger.decrement(); - } - }) - .start(); - } else { - // Animate the footer into view - animateFooterVisibility(true, 0); - } - ctx.postAnimationTrigger.increment(); - - } else if (mConfig.launchedFromAppWithThumbnail) { + if (mConfig.launchedFromAppWithThumbnail) { if (mTask.isLaunchTarget) { // Animate the dim/overlay if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) { @@ -381,16 +270,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } ctx.postAnimationTrigger.increment(); - // Animate the footer into view - animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration); - // Animate the action button in - mActionButtonView.animate().alpha(1f) - .setStartDelay(mConfig.taskBarEnterAnimDelay) - .setDuration(mConfig.taskBarEnterAnimDuration) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .withLayer() - .start(); + fadeInActionButton(true); } else { // Animate the task up if it was occluding the launch target if (ctx.currentTaskOccludesLaunchTarget) { @@ -442,14 +323,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, }) .start(); ctx.postAnimationTrigger.increment(); - - // Animate the footer into view - animateFooterVisibility(true, mConfig.taskViewEnterFromHomeDuration); startDelay = delay; - - } else { - // Animate the footer into view - animateFooterVisibility(true, 0); } // Enable the focus animations from this point onwards so that they aren't affected by the @@ -462,6 +336,21 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, }, (startDelay / 2)); } + public void fadeInActionButton(boolean withDelay) { + // Hide the action button + mActionButtonView.setAlpha(0f); + + // Animate the action button in + ViewPropertyAnimator animator = mActionButtonView.animate().alpha(1f) + .setDuration(mConfig.taskBarEnterAnimDuration) + .setInterpolator(PhoneStatusBar.ALPHA_IN) + .withLayer(); + if (withDelay) { + animator.setStartDelay(mConfig.taskBarEnterAnimDelay); + } + animator.start(); + } + /** Animates this task view as it leaves recents by pressing home. */ void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { animate() @@ -483,7 +372,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mThumbnailView.startLaunchTaskAnimation(postAnimRunnable); // Animate the dim - if (mDim > 0) { + if (mDimAlpha > 0) { ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0); anim.setDuration(mConfig.taskBarExitAnimDuration); anim.setInterpolator(mConfig.fastOutLinearInInterpolator); @@ -569,23 +458,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mCb.onTaskViewDismissed(tv); } }); - // Hide the footer - animateFooterVisibility(false, mConfig.taskViewRemoveAnimDuration); - } - - /** Sets whether this task view is full screen or not. */ - void setIsFullScreen(boolean isFullscreen) { - mIsFullScreenView = isFullscreen; - mHeaderView.setIsFullscreen(isFullscreen); - if (isFullscreen) { - // If we are full screen, then disable the bottom outline clip for the footer - mViewBounds.setOutlineClipBottom(0); - } - } - - /** Returns whether this task view should currently be drawn as a full screen view. */ - boolean isFullScreenView() { - return mIsFullScreenView; } /** @@ -593,7 +465,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * view. */ boolean shouldClipViewInStack() { - return mClipViewInStack && !mIsFullScreenView && (getVisibility() == View.VISIBLE); + return mClipViewInStack && (getVisibility() == View.VISIBLE); } /** Sets whether this view should be clipped, or clipped against. */ @@ -604,27 +476,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } - /** Gets the max footer height. */ - public int getMaxFooterHeight() { - if (mFooterView != null) { - return mFooterView.mMaxFooterHeight; - } else { - return 0; - } - } - - /** Animates the footer into and out of view. */ - void animateFooterVisibility(boolean visible, int duration) { - // Hide the footer if we are a full screen view - if (mIsFullScreenView) return; - // Hide the footer if the current task can not be locked to - if (!mTask.lockToTaskEnabled || !mTask.lockToThisTask) return; - // Otherwise, animate the visibility - if (mFooterView != null) { - mFooterView.animateFooterVisibility(visible, duration); - } - } - /** Sets the current task progress. */ public void setTaskProgress(float p) { mTaskProgress = p; @@ -639,26 +490,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Returns the current dim. */ public void setDim(int dim) { - mDim = dim; - if (mDimAnimator != null) { - mDimAnimator.removeAllListeners(); - mDimAnimator.cancel(); - } + mDimAlpha = dim; if (mConfig.useHardwareLayers) { // Defer setting hardware layers if we have not yet measured, or there is no dim to draw if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) { - if (mDimAnimator != null) { - mDimAnimator.removeAllListeners(); - mDimAnimator.cancel(); - } - - int inverse = 255 - mDim; - mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse)); - mLayerPaint.setColorFilter(mDimColorFilter); - mContent.setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint); + mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0)); + mDimLayerPaint.setColorFilter(mDimColorFilter); + mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); } } else { - float dimAlpha = mDim / 255.0f; + float dimAlpha = mDimAlpha / 255.0f; if (mThumbnailView != null) { mThumbnailView.setDimAlpha(dimAlpha); } @@ -670,7 +511,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Returns the current dim. */ public int getDim() { - return mDim; + return mDimAlpha; } /** Animates the dim to the task progress. */ @@ -706,11 +547,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * if the view is not currently visible, or we are in touch state (where we still want to keep * track of focus). */ - public void setFocusedTask() { + public void setFocusedTask(boolean animateFocusedState) { mIsFocused = true; if (mFocusAnimationsEnabled) { // Focus the header bar - mHeaderView.onTaskViewFocusChanged(true); + mHeaderView.onTaskViewFocusChanged(true, animateFocusedState); } // Update the thumbnail alpha with the focus mThumbnailView.onFocusChanged(true); @@ -732,7 +573,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mIsFocused = false; if (mFocusAnimationsEnabled) { // Un-focus the header bar - mHeaderView.onTaskViewFocusChanged(false); + mHeaderView.onTaskViewFocusChanged(false, true); } // Update the thumbnail alpha with the focus @@ -766,7 +607,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mFocusAnimationsEnabled = true; if (mIsFocused && !wasFocusAnimationsEnabled) { // Re-notify the header if we were focused and animations were not previously enabled - mHeaderView.onTaskViewFocusChanged(true); + mHeaderView.onTaskViewFocusChanged(true, true); } } @@ -776,15 +617,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskBound(Task t) { mTask = t; mTask.setCallbacks(this); - if (getMeasuredWidth() == 0) { - // If we haven't yet measured, we should just set the footer height with any animation - animateFooterVisibility(t.lockToThisTask, 0); - } else { - animateFooterVisibility(t.lockToThisTask, mConfig.taskViewLockToAppLongAnimDuration); - } - // Hide the action button if lock to app is disabled - if (!t.lockToTaskEnabled && mActionButtonView.getVisibility() != View.GONE) { - mActionButtonView.setVisibility(View.GONE); + + // Hide the action button if lock to app is disabled for this view + int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE; + if (mActionButtonView.getVisibility() != lockButtonVisibility) { + mActionButtonView.setVisibility(lockButtonVisibility); + requestLayout(); } } @@ -792,18 +630,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskDataLoaded() { if (mThumbnailView != null && mHeaderView != null) { // Bind each of the views to the new task data - if (mIsFullScreenView) { - mThumbnailView.bindToScreenshot(AlternateRecentsComponent.getLastScreenshot()); - } else { - mThumbnailView.rebindToTask(mTask); - } + mThumbnailView.rebindToTask(mTask); mHeaderView.rebindToTask(mTask); // Rebind any listeners mHeaderView.mApplicationIcon.setOnClickListener(this); mHeaderView.mDismissButton.setOnClickListener(this); - if (mFooterView != null) { - mFooterView.setOnClickListener(this); - } mActionButtonView.setOnClickListener(this); if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { if (mConfig.developerOptionsEnabled) { @@ -824,9 +655,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Unbind any listeners mHeaderView.mApplicationIcon.setOnClickListener(null); mHeaderView.mDismissButton.setOnClickListener(null); - if (mFooterView != null) { - mFooterView.setOnClickListener(null); - } mActionButtonView.setOnClickListener(null); if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { mHeaderView.mApplicationIcon.setOnLongClickListener(null); @@ -840,19 +668,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, setOnClickListener(enabled ? this : null); } - /**** TaskViewFooter.TaskFooterViewCallbacks ****/ - - @Override - public void onTaskFooterHeightChanged(int height, int maxHeight) { - if (mIsFullScreenView) { - // Disable the bottom outline clip when fullscreen - mViewBounds.setOutlineClipBottom(0); - } else { - // Update the bottom clip in our outline provider - mViewBounds.setOutlineClipBottom(maxHeight - height); - } - } - /**** View.OnClickListener Implementation ****/ @Override @@ -876,8 +691,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Reset the translation of the action button before we animate it out mActionButtonView.setTranslationZ(0f); } - mCb.onTaskViewClicked(tv, tv.getTask(), - (v == mFooterView || v == mActionButtonView)); + mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView)); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java deleted file mode 100644 index 324169e..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 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.recents.views; - -import android.animation.ObjectAnimator; -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; -import com.android.systemui.recents.RecentsConfiguration; - - -/** The task footer view */ -public class TaskViewFooter extends FrameLayout { - - interface TaskFooterViewCallbacks { - public void onTaskFooterHeightChanged(int height, int maxHeight); - } - - RecentsConfiguration mConfig; - - TaskFooterViewCallbacks mCb; - int mFooterHeight; - int mMaxFooterHeight; - ObjectAnimator mFooterAnimator; - - public TaskViewFooter(Context context) { - this(context, null); - } - - public TaskViewFooter(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - mConfig = RecentsConfiguration.getInstance(); - mMaxFooterHeight = mConfig.taskViewLockToAppButtonHeight; - setFooterHeight(getFooterHeight()); - } - - /** Sets the callbacks for when the footer height changes. */ - void setCallbacks(TaskFooterViewCallbacks cb) { - mCb = cb; - mCb.onTaskFooterHeightChanged(mFooterHeight, mMaxFooterHeight); - } - - /** Sets the footer height. */ - public void setFooterHeight(int footerHeight) { - if (footerHeight != mFooterHeight) { - mFooterHeight = footerHeight; - mCb.onTaskFooterHeightChanged(footerHeight, mMaxFooterHeight); - } - } - - /** Gets the footer height. */ - public int getFooterHeight() { - return mFooterHeight; - } - - /** Animates the footer into and out of view. */ - void animateFooterVisibility(final boolean visible, int duration) { - // Return early if there is no footer - if (mMaxFooterHeight <= 0) return; - - // Cancel the previous animation - if (mFooterAnimator != null) { - mFooterAnimator.removeAllListeners(); - mFooterAnimator.cancel(); - } - int finalHeight = visible ? mMaxFooterHeight : 0; - if (duration > 0) { - mFooterAnimator = ObjectAnimator.ofInt(this, "footerHeight", finalHeight); - mFooterAnimator.setDuration(duration); - mFooterAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mFooterAnimator.start(); - } else { - setFooterHeight(finalHeight); - } - } -} 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 396d441..ba868f5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -36,7 +36,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; -import android.graphics.drawable.ShapeDrawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -56,25 +55,27 @@ public class TaskViewHeader extends FrameLayout { RecentsConfiguration mConfig; + // Header views ImageView mDismissButton; ImageView mApplicationIcon; TextView mActivityDescription; - RippleDrawable mBackground; - GradientDrawable mBackgroundColorDrawable; + // Header drawables + boolean mCurrentPrimaryColorIsDark; + int mCurrentPrimaryColor; int mBackgroundColor; Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; + RippleDrawable mBackground; + GradientDrawable mBackgroundColorDrawable; AnimatorSet mFocusAnimator; - ValueAnimator backgroundColorAnimator; - PorterDuffColorFilter mDimFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); - - boolean mIsFullscreen; - boolean mCurrentPrimaryColorIsDark; - int mCurrentPrimaryColor; + // Static highlight that we draw at the top of each view static Paint sHighlightPaint; - private Paint mDimPaint = new Paint(); + + // Header dim, which is only used when task view hardware layers are not used + Paint mDimLayerPaint = new Paint(); + PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); public TaskViewHeader(Context context) { this(context, null); @@ -159,21 +160,14 @@ public class TaskViewHeader extends FrameLayout { @Override protected void onDraw(Canvas canvas) { - if (!mIsFullscreen) { - // Draw the highlight at the top edge (but put the bottom edge just out of view) - float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f); - float radius = mConfig.taskViewRoundedCornerRadiusPx; - int count = canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); - canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, - getMeasuredHeight() + radius, radius, radius, sHighlightPaint); - canvas.restoreToCount(count); - } - } - - /** Sets whether the current task is full screen or not. */ - void setIsFullscreen(boolean isFullscreen) { - mIsFullscreen = isFullscreen; + // Draw the highlight at the top edge (but put the bottom edge just out of view) + float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f); + float radius = mConfig.taskViewRoundedCornerRadiusPx; + int count = canvas.save(Canvas.CLIP_SAVE_FLAG); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, + getMeasuredHeight() + radius, radius, radius, sHighlightPaint); + canvas.restoreToCount(count); } @Override @@ -181,6 +175,16 @@ public class TaskViewHeader extends FrameLayout { return false; } + /** + * Sets the dim alpha, only used when we are not using hardware layers. + * (see RecentsConfiguration.useHardwareLayers) + */ + void setDimAlpha(int alpha) { + mDimColorFilter.setColor(Color.argb(alpha, 0, 0, 0)); + mDimLayerPaint.setColorFilter(mDimColorFilter); + setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); + } + /** Returns the secondary color for a primary color. */ int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) { int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK; @@ -268,13 +272,16 @@ public class TaskViewHeader extends FrameLayout { } /** Notifies the associated TaskView has been focused. */ - void onTaskViewFocusChanged(boolean focused) { + void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) { + // If we are not animating the visible state, just return + if (!animateFocusedState) return; + boolean isRunning = false; if (mFocusAnimator != null) { isRunning = mFocusAnimator.isRunning(); - mFocusAnimator.removeAllListeners(); - mFocusAnimator.cancel(); + Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator); } + if (focused) { int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark); int[][] states = new int[][] { @@ -349,11 +356,4 @@ public class TaskViewHeader extends FrameLayout { } } } - - public void setDimAlpha(int alpha) { - int color = Color.argb(alpha, 0, 0, 0); - mDimFilter.setColor(color); - mDimPaint.setColorFilter(mDimFilter); - setLayerType(LAYER_TYPE_HARDWARE, mDimPaint); - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index a946a84..c83248e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -33,37 +33,48 @@ import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; -/** The task thumbnail view */ +/** + * The task thumbnail view. It implements an image view that allows for animating the dim and + * alpha of the thumbnail image. + */ public class TaskViewThumbnail extends View { - private final int mCornerRadius; - private final Matrix mScaleMatrix = new Matrix(); RecentsConfiguration mConfig; - // Task bar clipping - Rect mClipRect = new Rect(); + // Drawing + float mDimAlpha; + Matrix mScaleMatrix = new Matrix(); Paint mDrawPaint = new Paint(); + RectF mBitmapRect = new RectF(); + RectF mLayoutRect = new RectF(); + BitmapShader mBitmapShader; LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); - private final RectF mBitmapRect = new RectF(); - private final RectF mLayoutRect = new RectF(); - private BitmapShader mBitmapShader; - private float mBitmapAlpha; - private float mDimAlpha; - private View mTaskBar; - private boolean mInvisible; - private ValueAnimator mAlphaAnimator; - private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener + + // Thumbnail alpha + float mThumbnailAlpha; + ValueAnimator mThumbnailAlphaAnimator; + ValueAnimator.AnimatorUpdateListener mThumbnailAlphaUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - mBitmapAlpha = (float) animation.getAnimatedValue(); - updateFilter(); + mThumbnailAlpha = (float) animation.getAnimatedValue(); + updateThumbnailPaintFilter(); } }; + // Task bar clipping, the top of this thumbnail can be clipped against the opaque header + // bar that overlaps this thumbnail + View mTaskBar; + Rect mClipRect = new Rect(); + + // Visibility optimization, if the thumbnail height is less than the height of the header + // bar for the task view, then just mark this thumbnail view as invisible + boolean mInvisible; + public TaskViewThumbnail(Context context) { this(context, null); } @@ -79,53 +90,82 @@ public class TaskViewThumbnail extends View { public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mConfig = RecentsConfiguration.getInstance(); - mCornerRadius = mConfig.taskViewRoundedCornerRadiusPx; mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setFilterBitmap(true); mDrawPaint.setAntiAlias(true); } @Override + protected void onFinishInflate() { + mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; + updateThumbnailPaintFilter(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + mLayoutRect.set(0, 0, getWidth(), getHeight()); + updateThumbnailScale(); + } + } + + @Override protected void onDraw(Canvas canvas) { if (mInvisible) { return; } - canvas.drawRoundRect(0, - 0, - getWidth(), - getHeight(), - mCornerRadius, - mCornerRadius, - mDrawPaint); + // Draw the thumbnail with the rounded corners + canvas.drawRoundRect(0, 0, getWidth(), getHeight(), + mConfig.taskViewRoundedCornerRadiusPx, + mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint); } - @Override - protected void onFinishInflate() { - mBitmapAlpha = 0.9f; - updateFilter(); + /** Sets the thumbnail to a given bitmap. */ + void setThumbnail(Bitmap bm) { + if (bm != null) { + mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP); + mDrawPaint.setShader(mBitmapShader); + mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight()); + updateThumbnailScale(); + } else { + mBitmapShader = null; + mDrawPaint.setShader(null); + } + updateThumbnailPaintFilter(); } - private void updateFilter() { + /** Updates the paint to draw the thumbnail. */ + void updateThumbnailPaintFilter() { if (mInvisible) { return; } - int mul = (int) ((1.0f - mDimAlpha) * mBitmapAlpha * 255); - int add = (int) ((1.0f - mDimAlpha) * (1 - mBitmapAlpha) * 255); + int mul = (int) ((1.0f - mDimAlpha) * mThumbnailAlpha * 255); + int add = (int) ((1.0f - mDimAlpha) * (1 - mThumbnailAlpha) * 255); if (mBitmapShader != null) { mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul)); mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add)); mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setColor(0xffffffff); } else { - mDrawPaint.setColorFilter(null); int grey = mul + add; + mDrawPaint.setColorFilter(null); mDrawPaint.setColor(Color.argb(255, grey, grey, grey)); } invalidate(); } + /** Updates the thumbnail shader's scale transform. */ + void updateThumbnailScale() { + if (mBitmapShader != null) { + mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL); + mBitmapShader.setLocalMatrix(mScaleMatrix); + } + } + /** Updates the clip rect based on the given task bar. */ - void enableTaskBarClip(View taskBar) { + void updateClipToTaskBar(View taskBar) { mTaskBar = taskBar; int top = (int) Math.max(0, taskBar.getTranslationY() + taskBar.getMeasuredHeight() - 1); @@ -133,75 +173,39 @@ public class TaskViewThumbnail extends View { setClipBounds(mClipRect); } - void updateVisibility(int clipBottom) { - boolean invisible = mTaskBar != null && getHeight() - clipBottom < mTaskBar.getHeight(); + /** Updates the visibility of the the thumbnail. */ + void updateThumbnailVisibility(int clipBottom) { + boolean invisible = mTaskBar != null && (getHeight() - clipBottom) <= mTaskBar.getHeight(); if (invisible != mInvisible) { mInvisible = invisible; if (!mInvisible) { - updateFilter(); + updateThumbnailPaintFilter(); } invalidate(); } } - /** Binds the thumbnail view to the screenshot. */ - boolean bindToScreenshot(Bitmap ss) { - setImageBitmap(ss); - return ss != null; - } - - /** Unbinds the thumbnail view from the screenshot. */ - void unbindFromScreenshot() { - setImageBitmap(null); + /** + * Sets the dim alpha, only used when we are not using hardware layers. + * (see RecentsConfiguration.useHardwareLayers) + */ + public void setDimAlpha(float dimAlpha) { + mDimAlpha = dimAlpha; + updateThumbnailPaintFilter(); } /** Binds the thumbnail view to the task */ void rebindToTask(Task t) { if (t.thumbnail != null) { - setImageBitmap(t.thumbnail); + setThumbnail(t.thumbnail); } else { - setImageBitmap(null); + setThumbnail(null); } } - public void setImageBitmap(Bitmap bm) { - if (bm != null) { - mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, - Shader.TileMode.CLAMP); - mDrawPaint.setShader(mBitmapShader); - mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight()); - updateBitmapScale(); - } else { - mBitmapShader = null; - mDrawPaint.setShader(null); - } - updateFilter(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - mLayoutRect.set(0, 0, getWidth(), getHeight()); - updateBitmapScale(); - } - } - - private void updateBitmapScale() { - if (mBitmapShader != null) { - mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL); - mBitmapShader.setLocalMatrix(mScaleMatrix); - } - } - - public void setDimAlpha(float dimAlpha) { - mDimAlpha = dimAlpha; - updateFilter(); - } - /** Unbinds the thumbnail view from the task */ void unbindFromTask() { - setImageBitmap(null); + setThumbnail(null); } /** Handles focus changes. */ @@ -217,54 +221,46 @@ public class TaskViewThumbnail extends View { } } - /** Prepares for the enter recents animation. */ + /** + * Prepares for the enter recents animation, this gets called before the the view + * is first visible and will be followed by a startEnterRecentsAnimation() call. + */ void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) { if (isTaskViewLaunchTargetTask) { - mBitmapAlpha = 1f; + mThumbnailAlpha = 1f; } else { - mBitmapAlpha = mConfig.taskViewThumbnailAlpha; + mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; } - updateFilter(); + updateThumbnailPaintFilter(); } - /** Animates this task thumbnail as it enters recents */ + /** Animates this task thumbnail as it enters Recents. */ void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) { startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay, mConfig.taskBarEnterAnimDuration, postAnimRunnable); } - /** Animates this task thumbnail as it exits recents */ + /** Animates this task thumbnail as it exits Recents. */ void startLaunchTaskAnimation(Runnable postAnimRunnable) { startFadeAnimation(1f, 0, mConfig.taskBarExitAnimDuration, postAnimRunnable); } - /** Animates the thumbnail alpha. */ + /** Starts a new thumbnail alpha animation. */ void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) { - if (mAlphaAnimator != null) { - mAlphaAnimator.cancel(); - } - mAlphaAnimator = ValueAnimator.ofFloat(mBitmapAlpha, finalAlpha); - mAlphaAnimator.addUpdateListener(mAlphaUpdateListener); - mAlphaAnimator.setStartDelay(delay); - mAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mAlphaAnimator.setDuration(duration); - mAlphaAnimator.start(); + Utilities.cancelAnimationWithoutCallbacks(mThumbnailAlphaAnimator); + mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha); + mThumbnailAlphaAnimator.setStartDelay(delay); + mThumbnailAlphaAnimator.setDuration(duration); + mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener); if (postAnimRunnable != null) { - mAlphaAnimator.addListener(new AnimatorListenerAdapter() { - public boolean mCancelled; - - @Override - public void onAnimationCancel(Animator animation) { - mCancelled = true; - } - + mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (!mCancelled) { - postAnimRunnable.run(); - } + postAnimRunnable.run(); } }); } + mThumbnailAlphaAnimator.start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index f5e5517..1b4bdf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -69,6 +69,7 @@ import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; import android.view.ViewStub; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -266,6 +267,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent); } + logActionClick(view); // The intent we are sending is for the application, which // won't have permission to immediately start an activity after // the user switches to home. We know it is safe to do at this @@ -295,7 +297,8 @@ public abstract class BaseStatusBar extends SystemUI implements // close the shade if it was open if (handled) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); visibilityChanged(false); } // Wait for activity start. @@ -308,6 +311,37 @@ public abstract class BaseStatusBar extends SystemUI implements } } + private void logActionClick(View view) { + ViewParent parent = view.getParent(); + String key = getNotificationKeyForParent(parent); + if (key == null) { + Log.w(TAG, "Couldn't determine notification for click."); + return; + } + int index = -1; + // If this is a default template, determine the index of the button. + if (view.getId() == com.android.internal.R.id.action0 && + parent != null && parent instanceof ViewGroup) { + ViewGroup actionGroup = (ViewGroup) parent; + index = actionGroup.indexOfChild(view); + } + try { + mBarService.onNotificationActionClick(key, index); + } catch (RemoteException e) { + // Ignore + } + } + + private String getNotificationKeyForParent(ViewParent parent) { + while (parent != null) { + if (parent instanceof ExpandableNotificationRow) { + return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey(); + } + parent = parent.getParent(); + } + return null; + } + private boolean superOnClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { return super.onClickHandler(view, pendingIntent, fillInIntent); @@ -341,7 +375,8 @@ public abstract class BaseStatusBar extends SystemUI implements Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); if (BANNER_ACTION_SETUP.equals(action)) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -766,7 +801,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } }); - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } }, false /* afterKeyguardGone */); @@ -1531,7 +1566,8 @@ public abstract class BaseStatusBar extends SystemUI implements }.start(); // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); visibilityChanged(false); return mIntent != null && mIntent.isActivity(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 9196dc8..556c423 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -158,6 +158,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public void resetHeight() { mMaxExpandHeight = 0; mWasReset = true; + mActualHeight = 0; onHeightReset(); requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index b71c9bf..9154a48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -49,7 +49,6 @@ public class SignalClusterView private boolean mIsAirplaneMode = false; private int mAirplaneIconId = 0; private String mWifiDescription, mMobileDescription, mMobileTypeDescription; - private boolean mRoaming; private boolean mIsMobileTypeIconWide; ViewGroup mWifiGroup, mMobileGroup; @@ -58,6 +57,8 @@ public class SignalClusterView View mWifiSignalSpacer; private int mWideTypeIconStartPadding; + private int mEndPadding; + private int mEndPaddingNothingVisible; public SignalClusterView(Context context) { this(context, null); @@ -88,6 +89,10 @@ public class SignalClusterView super.onFinishInflate(); mWideTypeIconStartPadding = getContext().getResources().getDimensionPixelSize( R.dimen.wide_type_icon_start_padding); + mEndPadding = getContext().getResources().getDimensionPixelSize( + R.dimen.signal_cluster_battery_padding); + mEndPaddingNothingVisible = getContext().getResources().getDimensionPixelSize( + R.dimen.no_signal_cluster_battery_padding); } @Override @@ -143,14 +148,12 @@ public class SignalClusterView @Override public void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, - String contentDescription, String typeContentDescription, boolean roaming, - boolean isTypeIconWide) { + String contentDescription, String typeContentDescription, boolean isTypeIconWide) { mMobileVisible = visible; mMobileStrengthId = strengthIcon; mMobileTypeId = typeIcon; mMobileDescription = contentDescription; mMobileTypeDescription = typeContentDescription; - mRoaming = roaming; mIsMobileTypeIconWide = isTypeIconWide; apply(); @@ -244,7 +247,7 @@ public class SignalClusterView mWifiAirplaneSpacer.setVisibility(View.GONE); } - if (mRoaming && mMobileVisible && mWifiVisible) { + if (mMobileVisible && mMobileTypeId != 0 && mWifiVisible) { mWifiSignalSpacer.setVisibility(View.VISIBLE); } else { mWifiSignalSpacer.setVisibility(View.GONE); @@ -257,7 +260,10 @@ public class SignalClusterView (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); - mMobileType.setVisibility((mRoaming || mMobileTypeId != 0) ? View.VISIBLE : View.GONE); + mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE); + + boolean anythingVisible = mWifiVisible || mIsAirplaneMode || mMobileVisible || mVpnVisible; + setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index c5d06b9..682c01c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -122,9 +122,14 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { } String cast = args.getString("cast"); if (cast != null) { - int iconId = cast.equals("cast") ? R.drawable.stat_sys_cast : 0; + int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0; updateSlot("cast", null, iconId); } + String hotspot = args.getString("hotspot"); + if (hotspot != null) { + int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0; + updateSlot("hotspot", null, iconId); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index dd5df12..598a35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -133,7 +133,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL if (action == ACTION_CLICK) { if (host == mLockIcon) { mPhoneStatusBar.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } else if (host == mCameraImageView) { launchCamera(); @@ -477,6 +477,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void onScreenTurnedOff(int why) { updateLockIcon(); } + + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + updateLockIcon(); + } }; public void setKeyguardIndicationController( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 650a14f..40c9134 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -36,6 +36,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserInfoController; +import java.text.NumberFormat; + /** * The header group on Keyguard. */ @@ -150,7 +152,8 @@ public class KeyguardStatusBarView extends RelativeLayout @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); + String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); + mBatteryLevel.setText(percentage); boolean changed = mBatteryCharging != charging; mBatteryCharging = charging; if (changed) { 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 a6fccb6..c19bdff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -802,6 +802,7 @@ public class NotificationPanelView extends PanelView implements requestPanelHeightUpdate(); mNotificationStackScroller.setInterceptDelegateEnabled(expanded); mStatusBar.setQsExpanded(expanded); + mQsPanel.setExpanded(expanded); } } 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 f74d2f4..3efaaff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -236,4 +236,8 @@ public class PanelBar extends FrameLayout { public void onExpandingFinished() { } + + public void onClosingFinished() { + + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index a7ff0bd..0ddda8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -68,7 +68,6 @@ public abstract class PanelView extends FrameLayout { protected int mTouchSlop; protected boolean mHintAnimationRunning; private boolean mOverExpandedBeforeFling; - private float mOriginalIndicationY; private boolean mTouchAboveFalsingThreshold; private int mUnlockFalsingThreshold; @@ -107,7 +106,7 @@ public abstract class PanelView extends FrameLayout { }; protected void onExpandingFinished() { - mClosing = false; + endClosing(); mBar.onExpandingFinished(); } @@ -250,9 +249,7 @@ public abstract class PanelView extends FrameLayout { trackMovement(event); if (!waitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) || mPeekPending || mPeekAnimator != null) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); cancelPeek(); mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning) || mPeekPending || mPeekAnimator != null; @@ -293,9 +290,7 @@ public abstract class PanelView extends FrameLayout { mInitialTouchY = y; h = 0; } - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); removeCallbacks(mPeekRunnable); mPeekPending = false; onTrackingStarted(); @@ -372,7 +367,7 @@ public abstract class PanelView extends FrameLayout { } protected void onTrackingStarted() { - mClosing = false; + endClosing(); mTracking = true; mCollapseAfterPeek = false; mBar.onTrackingStarted(PanelView.this); @@ -407,9 +402,7 @@ public abstract class PanelView extends FrameLayout { mStatusBar.userActivity(); if (mHeightAnimator != null && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); cancelPeek(); mTouchSlopExceeded = true; return true; @@ -441,9 +434,7 @@ public abstract class PanelView extends FrameLayout { trackMovement(event); if (scrolledToBottom) { if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); mInitialOffsetOnTouch = mExpandedHeight; mInitialTouchY = y; mInitialTouchX = x; @@ -461,6 +452,20 @@ public abstract class PanelView extends FrameLayout { return false; } + private void cancelHeightAnimator() { + if (mHeightAnimator != null) { + mHeightAnimator.cancel(); + } + endClosing(); + } + + private void endClosing() { + if (mClosing) { + mClosing = false; + onClosingFinished(); + } + } + private void initVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); @@ -700,9 +705,7 @@ public abstract class PanelView extends FrameLayout { mPeekRunnable.run(); } } else if (!isFullyCollapsed() && !mTracking && !mClosing) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); mClosing = true; notifyExpandingStarted(); if (delayed) { @@ -785,13 +788,16 @@ public abstract class PanelView extends FrameLayout { private void abortAnimations() { cancelPeek(); - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); removeCallbacks(mPostCollapseRunnable); removeCallbacks(mFlingCollapseRunnable); } + protected void onClosingFinished() { + mBar.onClosingFinished(); + } + + protected void startUnlockHintAnimation() { // We don't need to hint the user if an animation is already running or the user is changing @@ -841,16 +847,15 @@ public abstract class PanelView extends FrameLayout { }); animator.start(); mHeightAnimator = animator; - mOriginalIndicationY = mKeyguardBottomArea.getIndicationView().getY(); mKeyguardBottomArea.getIndicationView().animate() - .y(mOriginalIndicationY - mHintDistance) + .translationY(-mHintDistance) .setDuration(250) .setInterpolator(mFastOutSlowInInterpolator) .withEndAction(new Runnable() { @Override public void run() { mKeyguardBottomArea.getIndicationView().animate() - .y(mOriginalIndicationY) + .translationY(0) .setDuration(450) .setInterpolator(mBounceInterpolator) .start(); 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 9e3f0f6..9a33a36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -40,6 +40,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; +import android.content.ComponentCallbacks2; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -95,6 +96,7 @@ import android.view.ViewPropertyAnimator; import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateDecelerateInterpolator; @@ -173,6 +175,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; public class PhoneStatusBar extends BaseStatusBar implements DemoMode, DragDownHelper.DragDownCallback, ActivityStarter { @@ -581,7 +584,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, addNavigationBar(); // Lastly, call to the icon policy to install/update all the icons. - mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController); + mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController); mSettingsObserver.onChange(false); // set up mHeadsUpObserver.onChange(true); // set up @@ -798,7 +801,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mUserInfoController = new UserInfoController(mContext); mVolumeComponent = getComponent(VolumeComponent.class); - mZenModeController = mVolumeComponent.getZenController(); + if (mVolumeComponent != null) { + mZenModeController = mVolumeComponent.getZenController(); + } mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); @@ -2413,6 +2418,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); showBouncer(); disable(mDisabledUnmodified, true /* animate */); + + // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in + // the bouncer appear animation. + if (!mStatusBarKeyguardViewManager.isShowing()) { + WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + } } public boolean interceptTouchEvent(MotionEvent event) { @@ -2955,6 +2966,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mSecurityController != null) { mSecurityController.dump(fd, pw, args); } + pw.println("SharedPreferences:"); + for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(), + Context.MODE_PRIVATE).getAll().entrySet()) { + pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); + } } private String hunStateToString(Entry entry) { @@ -3036,7 +3052,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }); if (dismissShade) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); } return true; } @@ -3725,7 +3742,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public boolean onSpacePressed() { if (mScreenOn != null && mScreenOn && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { - animateCollapsePanels(0 /* flags */, true /* force */); + animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); return true; } return false; @@ -3779,6 +3797,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, runPostCollapseRunnables(); } + public void onClosingFinished() { + runPostCollapseRunnables(); + } + public void onUnlockHintStarted() { mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); } 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 47e1ab5..60d23ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -35,6 +35,7 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; +import com.android.systemui.statusbar.policy.HotspotController; /** * This class contains all of the policy about which icons are installed in the status @@ -49,6 +50,7 @@ public class PhoneStatusBarPolicy { private static final String SLOT_SYNC_ACTIVE = "sync_active"; private static final String SLOT_CAST = "cast"; + private static final String SLOT_HOTSPOT = "hotspot"; private static final String SLOT_BLUETOOTH = "bluetooth"; private static final String SLOT_TTY = "tty"; private static final String SLOT_ZEN = "zen"; @@ -60,6 +62,7 @@ public class PhoneStatusBarPolicy { private final StatusBarManager mService; private final Handler mHandler = new Handler(); private final CastController mCast; + private final HotspotController mHotspot; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. @@ -102,9 +105,10 @@ public class PhoneStatusBarPolicy { } }; - public PhoneStatusBarPolicy(Context context, CastController cast) { + public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) { mContext = context; mCast = cast; + mHotspot = hotspot; mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); // listen for broadcasts @@ -152,6 +156,11 @@ public class PhoneStatusBarPolicy { mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null); mService.setIconVisibility(SLOT_CAST, false); mCast.addCallback(mCastCallback); + + // hotspot + mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null); + mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); + mHotspot.addCallback(mHotspotCallback); } public void setZenMode(int zen) { @@ -300,6 +309,13 @@ public class PhoneStatusBarPolicy { mService.setIconVisibility(SLOT_CAST, isCasting); } + private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() { + @Override + public void onHotspotChanged(boolean enabled) { + mService.setIconVisibility(SLOT_HOTSPOT, enabled); + } + }; + private final CastController.Callback mCastCallback = new CastController.Callback() { @Override public void onCastDevicesChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 6411fb8..e4eae38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; import android.util.EventLog; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -152,6 +151,12 @@ public class PhoneStatusBarView extends PanelBar { } @Override + public void onClosingFinished() { + super.onClosingFinished(); + mBar.onClosingFinished(); + } + + @Override public void onTrackingStopped(PanelView panel, boolean expand) { super.onTrackingStopped(panel, expand); mBar.onTrackingStopped(expand); 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 2dc08d4..a4db46a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -120,6 +120,7 @@ public class QSTileHost implements QSTile.Host { tile.userSwitch(newUserId); } mSecurity.onUserSwitched(newUserId); + mNetwork.onUserSwitched(newUserId); mObserver.register(); } }; 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 b0f3ea1..247252c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -48,6 +48,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; +import java.text.NumberFormat; + /** * The view to manage the header area in the expanded status bar. */ @@ -300,9 +302,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateSystemIconsLayoutParams(); updateClickTargets(); updateMultiUserSwitch(); - if (mQSPanel != null) { - mQSPanel.setExpanded(mExpanded); - } updateClockScale(); updateAvatarScale(); updateClockLp(); @@ -395,7 +394,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); + String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); + mBatteryLevel.setText(percentage); } @Override 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 55c861a..65d231e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; @@ -24,6 +25,7 @@ import android.util.Slog; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.widget.LockPatternUtils; @@ -268,6 +270,8 @@ public class StatusBarKeyguardViewManager { public void run() { mStatusBarWindowManager.setKeyguardFadingAway(false); mPhoneStatusBar.finishKeyguardFadingAway(); + WindowManagerGlobal.getInstance().trimMemory( + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } }); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java index dcda2c7..b89aa8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java @@ -133,6 +133,7 @@ public class TrustDrawable extends Drawable { if (!mAnimating) { mAnimating = true; updateState(true); + invalidateSelf(); } } @@ -146,18 +147,21 @@ public class TrustDrawable extends Drawable { mState = STATE_UNSET; mCurAlpha = 0; mCurInnerRadius = mInnerRadiusEnter; + invalidateSelf(); } } public void setTrustManaged(boolean trustManaged) { if (trustManaged == mTrustManaged && mState != STATE_UNSET) return; mTrustManaged = trustManaged; - if (mAnimating) { - updateState(true); - } + updateState(true); } - private void updateState(boolean animate) { + private void updateState(boolean allowTransientState) { + if (!mAnimating) { + return; + } + int nextState = mState; if (mState == STATE_UNSET) { nextState = mTrustManaged ? STATE_ENTERING : STATE_GONE; @@ -170,7 +174,7 @@ public class TrustDrawable extends Drawable { } else if (mState == STATE_EXITING) { if (mTrustManaged) nextState = STATE_ENTERING; } - if (!animate) { + if (!allowTransientState) { if (nextState == STATE_ENTERING) nextState = STATE_VISIBLE; if (nextState == STATE_EXITING) nextState = STATE_GONE; } @@ -200,9 +204,8 @@ public class TrustDrawable extends Drawable { mState = nextState; if (mCurAnimator != null) { mCurAnimator.start(); - } else { - invalidateSelf(); } + invalidateSelf(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiAccessPointController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java index b800fbf..0a385d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiAccessPointController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java @@ -16,15 +16,20 @@ package com.android.systemui.statusbar.policy; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.ActionListener; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -39,9 +44,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -public class WifiAccessPointController { - private static final String TAG = "WifiAccessPointController"; - private static final boolean DEBUG = false; +public class AccessPointController { + private static final String TAG = "AccessPointController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + // This string extra specifies a network to open the connect dialog on, so the user can enter + // network credentials. This is used by quick settings for secured networks. + private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid"; private static final int[] ICONS = { R.drawable.ic_qs_wifi_0, @@ -54,13 +63,26 @@ public class WifiAccessPointController { private final Context mContext; private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>(); private final WifiManager mWifiManager; + private final UserManager mUserManager; private final Receiver mReceiver = new Receiver(); private boolean mScanning; + private int mCurrentUser; - public WifiAccessPointController(Context context) { + public AccessPointController(Context context) { mContext = context; mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mCurrentUser = ActivityManager.getCurrentUser(); + } + + public boolean canConfigWifi() { + return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, + new UserHandle(mCurrentUser)); + } + + void onUserSwitched(int newUserId) { + mCurrentUser = newUserId; } public void addCallback(AccessPointCallback callback) { @@ -81,22 +103,31 @@ public class WifiAccessPointController { if (mScanning) return; if (DEBUG) Log.d(TAG, "scan!"); mScanning = mWifiManager.startScan(); + // Grab current networks immediately while we wait for scan. + updateAccessPoints(); } - public void connect(AccessPoint ap) { - if (ap == null || ap.networkId < 0) return; + public boolean connect(AccessPoint ap) { + if (ap == null) return false; if (DEBUG) Log.d(TAG, "connect networkId=" + ap.networkId); - mWifiManager.connect(ap.networkId, new ActionListener() { - @Override - public void onSuccess() { - if (DEBUG) Log.d(TAG, "connect success"); - } - - @Override - public void onFailure(int reason) { - if (DEBUG) Log.d(TAG, "connect failure reason=" + reason); + if (ap.networkId < 0) { + // Unknown network, need to add it. + if (ap.hasSecurity) { + Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); + intent.putExtra(EXTRA_START_CONNECT_SSID, ap.ssid); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + return true; + } else { + WifiConfiguration config = new WifiConfiguration(); + config.SSID = "\"" + ap.ssid + "\""; + config.allowedKeyManagement.set(KeyMgmt.NONE); + mWifiManager.connect(config, mConnectListener); } - }); + } else { + mWifiManager.connect(ap.networkId, mConnectListener); + } + return false; } private void fireCallback(AccessPoint[] aps) { @@ -139,23 +170,40 @@ public class WifiAccessPointController { } final String ssid = scanResult.SSID; if (TextUtils.isEmpty(ssid) || ssids.contains(ssid)) continue; - if (!configured.containsKey(ssid)) continue; ssids.add(ssid); final WifiConfiguration config = configured.get(ssid); final int level = WifiManager.calculateSignalLevel(scanResult.level, ICONS.length); final AccessPoint ap = new AccessPoint(); + ap.isConfigured = config != null; ap.networkId = config != null ? config.networkId : AccessPoint.NO_NETWORK; ap.ssid = ssid; ap.iconId = ICONS[level]; ap.isConnected = ap.networkId != AccessPoint.NO_NETWORK && ap.networkId == connectedNetworkId; ap.level = level; + // Based on Settings AccessPoint#getSecurity, keep up to date + // with better methods of determining no security or not. + ap.hasSecurity = scanResult.capabilities.contains("WEP") + || scanResult.capabilities.contains("PSK") + || scanResult.capabilities.contains("EAP"); aps.add(ap); } Collections.sort(aps, mByStrength); fireCallback(aps.toArray(new AccessPoint[aps.size()])); } + private final ActionListener mConnectListener = new ActionListener() { + @Override + public void onSuccess() { + if (DEBUG) Log.d(TAG, "connect success"); + } + + @Override + public void onFailure(int reason) { + if (DEBUG) Log.d(TAG, "connect failure reason=" + reason); + } + }; + private final Comparator<AccessPoint> mByStrength = new Comparator<AccessPoint> () { @Override public int compare(AccessPoint lhs, AccessPoint rhs) { @@ -163,7 +211,7 @@ public class WifiAccessPointController { } private int score(AccessPoint ap) { - return ap.level + (ap.isConnected ? 10 : 0); + return ap.level + (ap.isConnected ? 20 : 0) + (ap.isConfigured ? 10 : 0); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index 6f021ac..33f7aff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -308,7 +308,11 @@ public class FlashlightController { new CameraCaptureSession.StateListener() { @Override public void onConfigured(CameraCaptureSession session) { - mSession = session; + if (session.getDevice() == mCameraDevice) { + mSession = session; + } else { + session.close(); + } postUpdateFlashlight(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 2ed9366..bb29d01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -39,11 +39,13 @@ public interface NetworkController { void addAccessPointCallback(AccessPointCallback callback); void removeAccessPointCallback(AccessPointCallback callback); void scanForAccessPoints(); - void connect(AccessPoint ap); + boolean connect(AccessPoint ap); boolean isMobileDataSupported(); boolean isMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); DataUsageInfo getDataUsageInfo(); + boolean canConfigWifi(); + void onUserSwitched(int newUserId); public interface AccessPointCallback { void onAccessPointsChanged(AccessPoint[] accessPoints); @@ -56,6 +58,8 @@ public interface NetworkController { public int iconId; public String ssid; public boolean isConnected; + public boolean isConfigured; + public boolean hasSecurity; public int level; // 0 - 5 } 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 3625997..6c0b425 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -164,12 +164,11 @@ public class NetworkControllerImpl extends BroadcastReceiver public interface SignalCluster { void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, - String contentDescription, String typeContentDescription, boolean roaming, - boolean isTypeIconWide); + String contentDescription, String typeContentDescription, boolean isTypeIconWide); void setIsAirplaneMode(boolean is, int airplaneIcon); } - private final WifiAccessPointController mAccessPoints; + private final AccessPointController mAccessPoints; private final MobileDataController mMobileDataController; /** @@ -240,7 +239,7 @@ public class NetworkControllerImpl extends BroadcastReceiver updateAirplaneMode(); mLastLocale = mContext.getResources().getConfiguration().locale; - mAccessPoints = new WifiAccessPointController(mContext); + mAccessPoints = new AccessPointController(mContext); mMobileDataController = new MobileDataController(mContext); mMobileDataController.setCallback(new MobileDataController.Callback() { @Override @@ -250,6 +249,16 @@ public class NetworkControllerImpl extends BroadcastReceiver }); } + @Override + public boolean canConfigWifi() { + return mAccessPoints.canConfigWifi(); + } + + @Override + public void onUserSwitched(int newUserId) { + mAccessPoints.onUserSwitched(newUserId); + } + private void notifyMobileDataEnabled(boolean enabled) { for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { cb.onMobileDataEnabled(enabled); @@ -314,8 +323,8 @@ public class NetworkControllerImpl extends BroadcastReceiver } @Override - public void connect(AccessPoint ap) { - mAccessPoints.connect(ap); + public boolean connect(AccessPoint ap) { + return mAccessPoints.connect(ap); } @Override @@ -386,7 +395,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDataTypeIconId, mContentDescriptionWimax, mContentDescriptionDataType, - mDataTypeIconId == TelephonyIcons.ROAMING_ICON, false /* isTypeIconWide */ ); } else { // normal mobile data @@ -396,7 +404,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDataTypeIconId, mContentDescriptionPhoneSignal, mContentDescriptionDataType, - mDataTypeIconId == TelephonyIcons.ROAMING_ICON, isTypeIconWide(mDataTypeIconId)); } cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId); @@ -1606,7 +1613,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDemoDataTypeIconId, "Demo", "Demo", - mDemoDataTypeIconId == TelephonyIcons.ROAMING_ICON, isTypeIconWide(mDemoDataTypeIconId)); } refreshViews(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java deleted file mode 100644 index f339401..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import android.content.Context; -import android.content.SharedPreferences; - -public class Prefs { - private static final String SHARED_PREFS_NAME = "status_bar"; - - public static SharedPreferences read(Context context) { - return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); - } - - public static SharedPreferences.Editor edit(Context context) { - return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit(); - } -} 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 eb808c2..5c7909a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -571,6 +571,9 @@ public class UserSwitcherController { cancel(); } else { dismiss(); + if (ActivityManager.isUserAMonkey()) { + return; + } UserInfo user = mUserManager.createSecondaryUser( mContext.getString(R.string.user_new_user_name), 0 /* flags */); if (user == null) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index 0586a83..0fe6d89 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -1,7 +1,6 @@ package com.android.systemui.volume; import android.content.Context; -import android.content.Intent; import android.content.res.Configuration; import android.database.ContentObserver; import android.media.AudioManager; @@ -11,13 +10,10 @@ import android.media.session.ISessionController; import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.os.RemoteException; -import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import android.view.WindowManagerGlobal; import com.android.systemui.R; import com.android.systemui.SystemUI; @@ -53,6 +49,7 @@ public class VolumeUI extends SystemUI { private final Handler mHandler = new Handler(); + private boolean mEnabled; private AudioManager mAudioManager; private MediaSessionManager mMediaSessionManager; private VolumeController mVolumeController; @@ -63,6 +60,8 @@ public class VolumeUI extends SystemUI { @Override public void start() { + mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui); + if (!mEnabled) return; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mMediaSessionManager = (MediaSessionManager) mContext .getSystemService(Context.MEDIA_SESSION_SERVICE); @@ -84,6 +83,7 @@ public class VolumeUI extends SystemUI { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.print("mEnabled="); pw.println(mEnabled); if (mPanel != null) { mPanel.dump(fd, pw, args); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index ea431ae..c840f17 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -31,6 +31,7 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; @@ -220,7 +221,8 @@ public class ZenModePanel extends LinearLayout { mBucketIndex = -1; } else { mBucketIndex = DEFAULT_BUCKET_INDEX; - mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + mTimeCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); mConditions = null; // reset conditions @@ -339,9 +341,11 @@ public class ZenModePanel extends LinearLayout { if (condition == null) return null; final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id); if (time == 0) return null; - final long span = time - System.currentTimeMillis(); + final long now = System.currentTimeMillis(); + final long span = time - now; if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null; - return ZenModeConfig.toTimeCondition(time, Math.round(span / (float) MINUTES_MS)); + return ZenModeConfig.toTimeCondition(mContext, + time, Math.round(span / (float) MINUTES_MS), now); } private void handleUpdateConditions(Condition[] conditions) { @@ -395,7 +399,7 @@ public class ZenModePanel extends LinearLayout { if (favoriteIndex == -1) { getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); } else { - mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[favoriteIndex]); + mTimeCondition = ZenModeConfig.toTimeCondition(mContext, MINUTE_BUCKETS[favoriteIndex]); mBucketIndex = favoriteIndex; bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); @@ -430,7 +434,8 @@ public class ZenModePanel extends LinearLayout { } tag.condition = condition; tag.rb.setEnabled(enabled); - if (sameConditionId(mSessionExitCondition, tag.condition)) { + if (mSessionExitCondition != null + && sameConditionId(mSessionExitCondition, tag.condition)) { tag.rb.setChecked(true); } tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { @@ -450,16 +455,32 @@ public class ZenModePanel extends LinearLayout { } }); - if (tag.title == null) { - tag.title = (TextView) row.findViewById(android.R.id.title); + if (tag.lines == null) { + tag.lines = row.findViewById(android.R.id.content); } + if (tag.line1 == null) { + tag.line1 = (TextView) row.findViewById(android.R.id.text1); + } + if (tag.line2 == null) { + tag.line2 = (TextView) row.findViewById(android.R.id.text2); + } + final String line1, line2; if (condition == null) { - tag.title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever)); + line1 = mContext.getString(com.android.internal.R.string.zen_mode_forever); + line2 = null; + } else { + line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1 : condition.summary; + line2 = condition.line2; + } + tag.line1.setText(line1); + if (TextUtils.isEmpty(line2)) { + tag.line2.setVisibility(GONE); } else { - tag.title.setText(condition.summary); + tag.line2.setVisibility(VISIBLE); + tag.line2.setText(line2); } - tag.title.setEnabled(enabled); - tag.title.setAlpha(enabled ? 1 : .4f); + tag.lines.setEnabled(enabled); + tag.lines.setAlpha(enabled ? 1 : .4f); final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1); button1.setOnClickListener(new OnClickListener() { @@ -476,7 +497,7 @@ public class ZenModePanel extends LinearLayout { onClickTimeButton(row, tag, true /*up*/); } }); - tag.title.setOnClickListener(new OnClickListener() { + tag.lines.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { tag.rb.setChecked(true); @@ -491,7 +512,8 @@ public class ZenModePanel extends LinearLayout { } else { final long span = time - System.currentTimeMillis(); button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS); - final Condition maxCondition = ZenModeConfig.toTimeCondition(MAX_BUCKET_MINUTES); + final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext, + MAX_BUCKET_MINUTES); button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary)); } @@ -504,7 +526,7 @@ public class ZenModePanel extends LinearLayout { // wire up interaction callbacks for newly-added condition rows if (convertView == null) { Interaction.register(tag.rb, mInteractionCallback); - Interaction.register(tag.title, mInteractionCallback); + Interaction.register(tag.lines, mInteractionCallback); Interaction.register(button1, mInteractionCallback); Interaction.register(button2, mInteractionCallback); } @@ -524,7 +546,7 @@ public class ZenModePanel extends LinearLayout { return; } announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText, - tag.title.getText())); + tag.line1.getText())); } private void onClickTimeButton(View row, ConditionTag tag, boolean up) { @@ -541,18 +563,21 @@ public class ZenModePanel extends LinearLayout { final long bucketTime = now + bucketMinutes * MINUTES_MS; if (up && bucketTime > time || !up && bucketTime < time) { mBucketIndex = j; - newCondition = ZenModeConfig.toTimeCondition(bucketTime, bucketMinutes); + newCondition = ZenModeConfig.toTimeCondition(mContext, + bucketTime, bucketMinutes, now); break; } } if (newCondition == null) { mBucketIndex = DEFAULT_BUCKET_INDEX; - newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + newCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } } else { // on a known index, simply increment or decrement mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1))); - newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + newCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } mTimeCondition = newCondition; bind(mTimeCondition, row); @@ -639,7 +664,9 @@ public class ZenModePanel extends LinearLayout { // used as the view tag on condition rows private static class ConditionTag { RadioButton rb; - TextView title; + View lines; + TextView line1; + TextView line2; Condition condition; } @@ -690,7 +717,7 @@ public class ZenModePanel extends LinearLayout { } private SharedPreferences prefs() { - return mContext.getSharedPreferences(ZenModePanel.class.getSimpleName(), 0); + return mContext.getSharedPreferences(mContext.getPackageName(), 0); } private void updateMinuteIndex() { |
