Loading packages/SystemUI/res/layout/shelf_menu_anchor.xml 0 → 100644 +24 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0"> <ImageView android:id="@+id/shelf_menu_anchor_anchor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:alpha="0"/> </FrameLayout> packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java +5 −1 Original line number Diff line number Diff line Loading @@ -34,11 +34,15 @@ class AppButtonData { this.pinned = pinned; } public int getTaskCount() { return tasks == null ? 0 : tasks.size(); } /** * Returns true if the button contains no useful information and should be removed. */ public boolean isEmpty() { return !pinned && (tasks == null || tasks.isEmpty()); return !pinned && getTaskCount() == 0; } public void addTask(RecentTaskInfo task) { Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java +109 −8 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Bundle; import android.os.RemoteException; Loading @@ -43,10 +44,14 @@ import android.util.AttributeSet; import android.util.Slog; import android.view.DragEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.Toast; import com.android.internal.content.PackageMonitor; Loading Loading @@ -78,6 +83,7 @@ class NavigationBarApps extends LinearLayout { private final UserManager mUserManager; private final LayoutInflater mLayoutInflater; private final AppPackageMonitor mAppPackageMonitor; private final WindowManager mWindowManager; // This view has two roles: Loading @@ -103,11 +109,22 @@ class NavigationBarApps extends LinearLayout { } }; // Layout params for the window that contains the anchor for the popup menus. // We need to create a window for a popup menu because the NavBar window is too narrow and can't // contain the menu. private final WindowManager.LayoutParams mPopupAnchorLayoutParams; // View that contains the anchor for popup menus. The view occupies the whole screen, and // has a child that will be moved to make the menu to appear where we need it. private final ViewGroup mPopupAnchor; private final PopupMenu mPopupMenu; private final int [] mClickedIconLocation = new int[2]; public NavigationBarApps(Context context, AttributeSet attrs) { super(context, attrs); sAppsModel = new NavigationBarAppsModel(context); mPackageManager = context.getPackageManager(); mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mLayoutInflater = LayoutInflater.from(context); mAppPackageMonitor = new AppPackageMonitor(); Loading @@ -131,6 +148,23 @@ class NavigationBarApps extends LinearLayout { } catch (RemoteException e) { Slog.e(TAG, "registerTaskStackListener failed", e); } mPopupAnchorLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); mPopupAnchorLayoutParams.setTitle("ShelfMenuAnchor"); mPopupAnchor = (ViewGroup) mLayoutInflater.inflate(R.layout.shelf_menu_anchor, null); ImageView anchorButton = (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor); mPopupMenu = new PopupMenu(context, anchorButton); } // Monitor that catches events like "app uninstalled". Loading Loading @@ -606,13 +640,11 @@ class NavigationBarApps extends LinearLayout { mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser()); } private void activateLatestTask(List<RecentTaskInfo> tasks) { // 'tasks' is guaranteed to be non-empty. int latestTaskPersistentId = tasks.get(0).persistentId; private void activateTask(int taskPersistentId) { // Launch or bring the activity to front. IActivityManager manager = ActivityManagerNative.getDefault(); try { manager.startActivityFromRecents(latestTaskPersistentId, null /* options */); manager.startActivityFromRecents(taskPersistentId, null /* options */); } catch (RemoteException e) { Slog.e(TAG, "Exception when activating a recent task", e); } catch (IllegalArgumentException e) { Loading @@ -620,14 +652,83 @@ class NavigationBarApps extends LinearLayout { } } /** * Adds to the popup menu items for activating each of tasks in the specified list. */ void populateLaunchMenu(List<RecentTaskInfo> tasks) { Menu menu = mPopupMenu.getMenu(); int taskCount = tasks.size(); for (int i = 0; i < taskCount; ++i) { final RecentTaskInfo taskInfo = tasks.get(i); MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString()); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @java.lang.Override public boolean onMenuItemClick(MenuItem item) { activateTask(taskInfo.persistentId); return true; } }); } } /** * Shows a task selection menu for clicked apps that have more than 1 running tasks. */ void maybeShowLaunchMenu(ImageView appIcon) { final AppButtonData appButtonData = (AppButtonData) appIcon.getTag(); if (appButtonData.getTaskCount() <= 1) return; // Movable view inside the popup anchor view. It serves as the actual anchor for the // menu. final ImageView anchorButton = (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor); // Set same drawable as for the clicked button to have same size. anchorButton.setImageDrawable(appIcon.getDrawable()); // Move the anchor button to the position of the app button. appIcon.getLocationOnScreen(mClickedIconLocation); anchorButton.setTranslationX(mClickedIconLocation[0]); anchorButton.setTranslationY(mClickedIconLocation[1]); final OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener() { @java.lang.Override public void onViewAttachedToWindow(View v) { mPopupMenu.show(); } @java.lang.Override public void onViewDetachedFromWindow(View v) {} }; anchorButton.addOnAttachStateChangeListener(onAttachStateChangeListener); populateLaunchMenu(appButtonData.tasks); mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { @java.lang.Override public void onDismiss(PopupMenu menu) { mWindowManager.removeView(mPopupAnchor); anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener); mPopupMenu.setOnDismissListener(null); mPopupMenu.getMenu().clear(); } }); mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams); } @Override public void onClick(View v) { AppButtonData appButtonData = (AppButtonData) v.getTag(); if (appButtonData.tasks == null || appButtonData.tasks.size() == 0) { if (appButtonData.getTaskCount() == 0) { launchApp(appButtonData.appInfo, v); } else { activateLatestTask(appButtonData.tasks); // Activate latest task. activateTask(appButtonData.tasks.get(0).persistentId); maybeShowLaunchMenu((ImageView) v); } } } Loading Loading
packages/SystemUI/res/layout/shelf_menu_anchor.xml 0 → 100644 +24 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0"> <ImageView android:id="@+id/shelf_menu_anchor_anchor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:alpha="0"/> </FrameLayout>
packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java +5 −1 Original line number Diff line number Diff line Loading @@ -34,11 +34,15 @@ class AppButtonData { this.pinned = pinned; } public int getTaskCount() { return tasks == null ? 0 : tasks.size(); } /** * Returns true if the button contains no useful information and should be removed. */ public boolean isEmpty() { return !pinned && (tasks == null || tasks.isEmpty()); return !pinned && getTaskCount() == 0; } public void addTask(RecentTaskInfo task) { Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java +109 −8 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Bundle; import android.os.RemoteException; Loading @@ -43,10 +44,14 @@ import android.util.AttributeSet; import android.util.Slog; import android.view.DragEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.Toast; import com.android.internal.content.PackageMonitor; Loading Loading @@ -78,6 +83,7 @@ class NavigationBarApps extends LinearLayout { private final UserManager mUserManager; private final LayoutInflater mLayoutInflater; private final AppPackageMonitor mAppPackageMonitor; private final WindowManager mWindowManager; // This view has two roles: Loading @@ -103,11 +109,22 @@ class NavigationBarApps extends LinearLayout { } }; // Layout params for the window that contains the anchor for the popup menus. // We need to create a window for a popup menu because the NavBar window is too narrow and can't // contain the menu. private final WindowManager.LayoutParams mPopupAnchorLayoutParams; // View that contains the anchor for popup menus. The view occupies the whole screen, and // has a child that will be moved to make the menu to appear where we need it. private final ViewGroup mPopupAnchor; private final PopupMenu mPopupMenu; private final int [] mClickedIconLocation = new int[2]; public NavigationBarApps(Context context, AttributeSet attrs) { super(context, attrs); sAppsModel = new NavigationBarAppsModel(context); mPackageManager = context.getPackageManager(); mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mLayoutInflater = LayoutInflater.from(context); mAppPackageMonitor = new AppPackageMonitor(); Loading @@ -131,6 +148,23 @@ class NavigationBarApps extends LinearLayout { } catch (RemoteException e) { Slog.e(TAG, "registerTaskStackListener failed", e); } mPopupAnchorLayoutParams = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); mPopupAnchorLayoutParams.setTitle("ShelfMenuAnchor"); mPopupAnchor = (ViewGroup) mLayoutInflater.inflate(R.layout.shelf_menu_anchor, null); ImageView anchorButton = (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor); mPopupMenu = new PopupMenu(context, anchorButton); } // Monitor that catches events like "app uninstalled". Loading Loading @@ -606,13 +640,11 @@ class NavigationBarApps extends LinearLayout { mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser()); } private void activateLatestTask(List<RecentTaskInfo> tasks) { // 'tasks' is guaranteed to be non-empty. int latestTaskPersistentId = tasks.get(0).persistentId; private void activateTask(int taskPersistentId) { // Launch or bring the activity to front. IActivityManager manager = ActivityManagerNative.getDefault(); try { manager.startActivityFromRecents(latestTaskPersistentId, null /* options */); manager.startActivityFromRecents(taskPersistentId, null /* options */); } catch (RemoteException e) { Slog.e(TAG, "Exception when activating a recent task", e); } catch (IllegalArgumentException e) { Loading @@ -620,14 +652,83 @@ class NavigationBarApps extends LinearLayout { } } /** * Adds to the popup menu items for activating each of tasks in the specified list. */ void populateLaunchMenu(List<RecentTaskInfo> tasks) { Menu menu = mPopupMenu.getMenu(); int taskCount = tasks.size(); for (int i = 0; i < taskCount; ++i) { final RecentTaskInfo taskInfo = tasks.get(i); MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString()); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @java.lang.Override public boolean onMenuItemClick(MenuItem item) { activateTask(taskInfo.persistentId); return true; } }); } } /** * Shows a task selection menu for clicked apps that have more than 1 running tasks. */ void maybeShowLaunchMenu(ImageView appIcon) { final AppButtonData appButtonData = (AppButtonData) appIcon.getTag(); if (appButtonData.getTaskCount() <= 1) return; // Movable view inside the popup anchor view. It serves as the actual anchor for the // menu. final ImageView anchorButton = (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor); // Set same drawable as for the clicked button to have same size. anchorButton.setImageDrawable(appIcon.getDrawable()); // Move the anchor button to the position of the app button. appIcon.getLocationOnScreen(mClickedIconLocation); anchorButton.setTranslationX(mClickedIconLocation[0]); anchorButton.setTranslationY(mClickedIconLocation[1]); final OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener() { @java.lang.Override public void onViewAttachedToWindow(View v) { mPopupMenu.show(); } @java.lang.Override public void onViewDetachedFromWindow(View v) {} }; anchorButton.addOnAttachStateChangeListener(onAttachStateChangeListener); populateLaunchMenu(appButtonData.tasks); mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() { @java.lang.Override public void onDismiss(PopupMenu menu) { mWindowManager.removeView(mPopupAnchor); anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener); mPopupMenu.setOnDismissListener(null); mPopupMenu.getMenu().clear(); } }); mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams); } @Override public void onClick(View v) { AppButtonData appButtonData = (AppButtonData) v.getTag(); if (appButtonData.tasks == null || appButtonData.tasks.size() == 0) { if (appButtonData.getTaskCount() == 0) { launchApp(appButtonData.appInfo, v); } else { activateLatestTask(appButtonData.tasks); // Activate latest task. activateTask(appButtonData.tasks.get(0).persistentId); maybeShowLaunchMenu((ImageView) v); } } } Loading