1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.keyboard;
18 
19 import android.view.Menu;
20 import android.view.MenuItem;
21 import android.view.View;
22 import android.view.accessibility.AccessibilityNodeInfo;
23 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
24 import android.widget.PopupMenu;
25 import android.widget.PopupMenu.OnMenuItemClickListener;
26 
27 import com.android.launcher3.popup.PopupContainerWithArrow;
28 import com.android.launcher3.ItemInfo;
29 import com.android.launcher3.Launcher;
30 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
31 
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
35 
36 /**
37  * Handles showing a popup menu with available custom actions for a launcher icon.
38  * This allows exposing various custom actions using keyboard shortcuts.
39  */
40 public class CustomActionsPopup implements OnMenuItemClickListener {
41 
42     private final Launcher mLauncher;
43     private final LauncherAccessibilityDelegate mDelegate;
44     private final View mIcon;
45 
CustomActionsPopup(Launcher launcher, View icon)46     public CustomActionsPopup(Launcher launcher, View icon) {
47         mLauncher = launcher;
48         mIcon = icon;
49         PopupContainerWithArrow container = PopupContainerWithArrow.getOpen(launcher);
50         if (container != null) {
51             mDelegate = container.getAccessibilityDelegate();
52         } else {
53             mDelegate = launcher.getAccessibilityDelegate();
54         }
55     }
56 
getActionList()57     private List<AccessibilityAction> getActionList() {
58         if (mIcon == null || !(mIcon.getTag() instanceof ItemInfo)) {
59             return Collections.EMPTY_LIST;
60         }
61 
62         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
63         mDelegate.addSupportedActions(mIcon, info, true);
64         List<AccessibilityAction> result = new ArrayList<>(info.getActionList());
65         info.recycle();
66         return result;
67     }
68 
canShow()69     public boolean canShow() {
70         return !getActionList().isEmpty();
71     }
72 
show()73     public boolean show() {
74         List<AccessibilityAction> actions = getActionList();
75         if (actions.isEmpty()) {
76             return false;
77         }
78 
79         PopupMenu popup = new PopupMenu(mLauncher, mIcon);
80         popup.setOnMenuItemClickListener(this);
81         Menu menu = popup.getMenu();
82         for (AccessibilityAction action : actions) {
83             menu.add(Menu.NONE, action.getId(), Menu.NONE, action.getLabel());
84         }
85         popup.show();
86         return true;
87     }
88 
89     @Override
onMenuItemClick(MenuItem menuItem)90     public boolean onMenuItemClick(MenuItem menuItem) {
91         return mDelegate.performAction(mIcon, (ItemInfo) mIcon.getTag(), menuItem.getItemId());
92     }
93 }
94