summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/layout/navigation_bar_with_apps.xml74
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java134
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
4 files changed, 110 insertions, 130 deletions
diff --git a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml b/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
index 4c06123968d4..d29b90025ef0 100644
--- a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
+++ b/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
@@ -91,42 +91,10 @@
android:src="@drawable/nav_app_divider"
/>
- <!-- TODO: Build the list of icons dynamically. -->
<com.android.systemui.statusbar.phone.NavigationBarRecents
android:layout_width="wrap_content"
android:layout_height="match_parent"
- >
- <ImageView android:id="@+id/recent0"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- <ImageView android:id="@+id/recent1"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- <ImageView android:id="@+id/recent2"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- </com.android.systemui.statusbar.phone.NavigationBarRecents>
+ />
</LinearLayout>
<FrameLayout
@@ -287,42 +255,10 @@
android:src="@drawable/nav_app_divider"
/>
- <!-- TODO: Build the list of icons dynamically. -->
- <com.android.systemui.statusbar.phone.NavigationBarRecents
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- >
- <ImageView android:id="@+id/recent0"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- <ImageView android:id="@+id/recent1"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- <ImageView android:id="@+id/recent2"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:padding="6dp"
- android:layout_gravity="center"
- android:scaleType="centerInside"
- android:visibility="invisible"
- />
- </com.android.systemui.statusbar.phone.NavigationBarRecents>
+ <com.android.systemui.statusbar.phone.NavigationBarRecents
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ />
</LinearLayout>
<FrameLayout
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index ddbcd331da69..ce2dd458be80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -29,7 +29,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -111,21 +111,29 @@ class NavigationBarApps extends LinearLayout {
return button;
}
+ // Not shared with NavigationBarRecents because the data model is specific to pinned apps.
private class AppLongClickListener implements View.OnLongClickListener {
@Override
public boolean onLongClick(View v) {
mDragView = v;
+ ImageView icon = (ImageView) v;
ComponentName activityName = mAppsModel.getApp(indexOfChild(v));
- // The drag data is an Intent to launch the activity.
- Intent mainIntent = Intent.makeMainActivity(activityName);
- ClipData dragData = ClipData.newIntent("", mainIntent);
- // Use the ImageView to create the shadow.
- View.DragShadowBuilder shadow = new AppIconDragShadowBuilder((ImageView) v);
- v.startDrag(dragData, shadow, null /* myLocalState */, 0 /* flags */);
+ startAppDrag(icon, activityName);
return true;
}
}
+ /** Helper function to start dragging an app icon (either pinned or recent). */
+ static void startAppDrag(ImageView icon, ComponentName activityName) {
+ // The drag data is an Intent to launch the activity.
+ Intent mainIntent = Intent.makeMainActivity(activityName);
+ ClipData dragData = ClipData.newIntent("", mainIntent);
+ // Use the ImageView to create the shadow.
+ View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
+ // Use a global drag because the icon might be dragged into the launcher.
+ icon.startDrag(dragData, shadow, null /* myLocalState */, View.DRAG_FLAG_GLOBAL);
+ }
+
@Override
public boolean dispatchDragEvent(DragEvent event) {
// ACTION_DRAG_ENTERED is handled by each individual app icon drag listener.
@@ -161,7 +169,7 @@ class NavigationBarApps extends LinearLayout {
* an app shortcut and will be accepted for a drop.
*/
private boolean onDragStarted(DragEvent event) {
- if (DEBUG) Log.d(TAG, "onDragStarted");
+ if (DEBUG) Slog.d(TAG, "onDragStarted");
// Ensure that an app shortcut is being dragged.
if (!canAcceptDrag(event)) {
@@ -194,7 +202,7 @@ class NavigationBarApps extends LinearLayout {
* needs to use LinearLayout/ViewGroup methods.
*/
private void onDragEnteredIcon(View target) {
- if (DEBUG) Log.d(TAG, "onDragEntered " + indexOfChild(target));
+ if (DEBUG) Slog.d(TAG, "onDragEntered " + indexOfChild(target));
// If the drag didn't start from an existing icon, add an invisible placeholder to create
// empty space for the user to drag into.
@@ -227,7 +235,7 @@ class NavigationBarApps extends LinearLayout {
}
private boolean onDrop(DragEvent event) {
- if (DEBUG) Log.d(TAG, "onDrop");
+ if (DEBUG) Slog.d(TAG, "onDrop");
int dragViewIndex = indexOfChild(mDragView);
if (mAppsModel.getApp(dragViewIndex) == null) {
@@ -285,7 +293,7 @@ class NavigationBarApps extends LinearLayout {
/** Cleans up at the end of the drag. */
private boolean onDragEnded() {
- if (DEBUG) Log.d(TAG, "onDragEnded");
+ if (DEBUG) Slog.d(TAG, "onDragEnded");
if (mDragView != null) {
// The icon wasn't dropped into the app list. Remove the placeholder.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
index 64bca34b2160..a645e2267968 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
@@ -20,7 +20,6 @@ import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ITaskStackListener;
-import android.content.ClipData;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -28,7 +27,10 @@ import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -36,6 +38,7 @@ import android.widget.LinearLayout;
import com.android.systemui.R;
import java.util.List;
+import java.util.Set;
/**
* Recent task icons appearing in the navigation bar. Touching an icon brings the activity to the
@@ -43,21 +46,31 @@ import java.util.List;
* icons.
*/
class NavigationBarRecents extends LinearLayout {
+ private final static boolean DEBUG = false;
private final static String TAG = "NavigationBarRecents";
- private final static int[] RECENT_APP_BUTTON_IDS = { R.id.recent0, R.id.recent1, R.id.recent2 };
+ // Maximum number of icons to show.
+ // TODO: Implement an overflow UI so the shelf can display an unlimited number of recents.
+ private final static int MAX_RECENTS = 10;
private final ActivityManager mActivityManager;
private final PackageManager mPackageManager;
+ private final LayoutInflater mLayoutInflater;
private final TaskStackListenerImpl mTaskStackListener;
+ // Recent tasks being displayed in the shelf.
+ private final Set<ComponentName> mCurrentTasks = new ArraySet<ComponentName>(MAX_RECENTS);
public NavigationBarRecents(Context context, AttributeSet attrs) {
super(context, attrs);
mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mPackageManager = getContext().getPackageManager();
+ mLayoutInflater = LayoutInflater.from(context);
// Listen for task stack changes and refresh when they happen. Update notifications happen
// on an IPC thread, so use Handler to handle the message on the main thread.
+ // TODO: This has too much latency. It only adds the icon when app launch is completed
+ // and the launch animation is done playing. This class should add the icon immediately
+ // when the launch starts.
Handler handler = new Handler();
mTaskStackListener = new TaskStackListenerImpl(handler);
IActivityManager iam = ActivityManagerNative.getDefault();
@@ -68,54 +81,86 @@ class NavigationBarRecents extends LinearLayout {
}
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- // Set up the buttons.
- for (int i = 0; i < RECENT_APP_BUTTON_IDS.length; i++) {
- ImageView button = getRecentAppButton(i);
- button.setOnLongClickListener(AppLongClickListener.getInstance());
- }
-
- // TODO: When is the right time to do the initial update?
- updateRecentApps();
- }
-
- private ImageView getRecentAppButton(int index) {
- return (ImageView) findViewById(RECENT_APP_BUTTON_IDS[index]);
- }
-
private void updateRecentApps() {
// TODO: Should this be getRunningTasks?
- List<ActivityManager.RecentTaskInfo> tasks = mActivityManager.getRecentTasksForUser(
- RECENT_APP_BUTTON_IDS.length,
+ // TODO: Query other UserHandles?
+ List<ActivityManager.RecentTaskInfo> recentTasks = mActivityManager.getRecentTasksForUser(
+ MAX_RECENTS,
ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
ActivityManager.RECENT_INCLUDE_PROFILES |
ActivityManager.RECENT_WITH_EXCLUDED,
UserHandle.USER_CURRENT);
- // Show the recent icons with the oldest on the left.
- int buttonIndex = 0;
- int taskIndex = tasks.size() - 1;
- while (taskIndex >= 0 && buttonIndex < RECENT_APP_BUTTON_IDS.length) {
- updateRecentAppButton(getRecentAppButton(buttonIndex), tasks.get(taskIndex));
- taskIndex--;
- buttonIndex++;
+ if (DEBUG) Slog.d(TAG, "Got recents " + recentTasks.size());
+ removeMissingRecents(recentTasks);
+ addNewRecents(recentTasks);
+ }
+
+ // Remove any icons that disappeared from recents.
+ private void removeMissingRecents(List<ActivityManager.RecentTaskInfo> recentTasks) {
+ // Extract the component names.
+ Set<ComponentName> recentComponents = new ArraySet<ComponentName>(recentTasks.size());
+ for (ActivityManager.RecentTaskInfo task : recentTasks) {
+ ComponentName component = task.baseIntent.getComponent();
+ if (component == null) { // It's unclear if this can happen in practice.
+ continue;
+ }
+ recentComponents.add(component);
}
- // Hide the unused buttons.
- while (buttonIndex < RECENT_APP_BUTTON_IDS.length) {
- hideButton(getRecentAppButton(buttonIndex));
- buttonIndex++;
+
+ // Start with a copy of the currently displayed tasks.
+ Set<ComponentName> removed = new ArraySet<ComponentName>(mCurrentTasks);
+ // Remove all the entries that still exist in recents.
+ removed.removeAll(recentComponents);
+ // The remaining entries no longer exist in recents, so remove their icons.
+ for (ComponentName task : removed) {
+ removeIcon(task);
}
}
- private void updateRecentAppButton(ImageView button, ActivityManager.RecentTaskInfo task) {
- ComponentName component = task.baseIntent.getComponent();
- if (component == null) {
- hideButton(button);
- return;
+ // Removes the icon for a task.
+ private void removeIcon(ComponentName task) {
+ for (int i = 0; i < getChildCount(); i++) {
+ ComponentName childTask = (ComponentName) getChildAt(i).getTag();
+ if (childTask.equals(task)) {
+ if (DEBUG) Slog.d(TAG, "removing missing " + task);
+ removeViewAt(i);
+ mCurrentTasks.remove(task);
+ return;
+ }
}
+ }
+
+ // Adds new tasks at the end of the icon list.
+ private void addNewRecents(List<ActivityManager.RecentTaskInfo> recentTasks) {
+ for (ActivityManager.RecentTaskInfo task : recentTasks) {
+ // Don't overflow the list.
+ if (getChildCount() >= MAX_RECENTS) {
+ return;
+ }
+ ComponentName component = task.baseIntent.getComponent();
+ if (component == null) { // It's unclear if this can happen in practice.
+ continue;
+ }
+ // Don't add tasks that are already being shown.
+ if (mCurrentTasks.contains(component)) {
+ continue;
+ }
+ addRecentAppButton(task);
+ }
+ }
+
+ // Adds an icon at the end of the list to represent an activity for a given component.
+ private void addRecentAppButton(ActivityManager.RecentTaskInfo task) {
+ // Add this task to the currently-shown set.
+ ComponentName component = task.baseIntent.getComponent();
+ mCurrentTasks.add(component);
+ if (DEBUG) Slog.d(TAG, "adding " + component);
+
+ ImageView button = (ImageView) mLayoutInflater.inflate(
+ R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
+ button.setOnLongClickListener(AppLongClickListener.getInstance());
+ addView(button);
// Use the View's tag to store metadata for drag and drop.
button.setTag(component);
@@ -134,11 +179,6 @@ class NavigationBarRecents extends LinearLayout {
});
}
- private void hideButton(ImageView button) {
- button.setImageDrawable(null);
- button.setVisibility(View.GONE);
- }
-
/**
* A listener that updates the app buttons whenever the recents task stack changes.
* NOTE: This is not the right way to do this.
@@ -173,13 +213,9 @@ class NavigationBarRecents extends LinearLayout {
@Override
public boolean onLongClick(View v) {
+ ImageView icon = (ImageView) v;
ComponentName activityName = (ComponentName) v.getTag();
- // The drag data is an Intent to launch the activity.
- Intent mainIntent = Intent.makeMainActivity(activityName);
- ClipData dragData = ClipData.newIntent("", mainIntent);
- // Use the ImageView to create the shadow.
- View.DragShadowBuilder shadow = new AppIconDragShadowBuilder((ImageView) v);
- v.startDrag(dragData, shadow, null /* myLocalState */, 0 /* flags */);
+ NavigationBarApps.startAppDrag(icon, activityName);
return true;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8431da215be6..3a83b6c79970 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -391,7 +391,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int LAST_PREBOOT_DELIVERED_FILE_VERSION = 10000;
// Delay in notifying task stack change listeners (in millis)
- static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 1000;
+ static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
// Necessary ApplicationInfo flags to mark an app as persistent
private static final int PERSISTENT_MASK =