• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.wm.shell;
18 
19 import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
20 
21 import com.android.wm.shell.apppairs.AppPairsController;
22 import com.android.wm.shell.common.ShellExecutor;
23 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
24 import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
25 import com.android.wm.shell.onehanded.OneHandedController;
26 import com.android.wm.shell.pip.Pip;
27 import com.android.wm.shell.splitscreen.SplitScreenController;
28 
29 import java.io.PrintWriter;
30 import java.util.Optional;
31 
32 /**
33  * An entry point into the shell for dumping shell internal state and running adb commands.
34  *
35  * Use with {@code adb shell dumpsys activity service SystemUIService WMShell ...}.
36  */
37 public final class ShellCommandHandlerImpl {
38     private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
39 
40     private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
41     private final Optional<SplitScreenController> mSplitScreenOptional;
42     private final Optional<Pip> mPipOptional;
43     private final Optional<OneHandedController> mOneHandedOptional;
44     private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
45     private final Optional<AppPairsController> mAppPairsOptional;
46     private final ShellTaskOrganizer mShellTaskOrganizer;
47     private final ShellExecutor mMainExecutor;
48     private final HandlerImpl mImpl = new HandlerImpl();
49 
ShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional<LegacySplitScreenController> legacySplitScreenOptional, Optional<SplitScreenController> splitScreenOptional, Optional<Pip> pipOptional, Optional<OneHandedController> oneHandedOptional, Optional<HideDisplayCutoutController> hideDisplayCutout, Optional<AppPairsController> appPairsOptional, ShellExecutor mainExecutor)50     public ShellCommandHandlerImpl(
51             ShellTaskOrganizer shellTaskOrganizer,
52             Optional<LegacySplitScreenController> legacySplitScreenOptional,
53             Optional<SplitScreenController> splitScreenOptional,
54             Optional<Pip> pipOptional,
55             Optional<OneHandedController> oneHandedOptional,
56             Optional<HideDisplayCutoutController> hideDisplayCutout,
57             Optional<AppPairsController> appPairsOptional,
58             ShellExecutor mainExecutor) {
59         mShellTaskOrganizer = shellTaskOrganizer;
60         mLegacySplitScreenOptional = legacySplitScreenOptional;
61         mSplitScreenOptional = splitScreenOptional;
62         mPipOptional = pipOptional;
63         mOneHandedOptional = oneHandedOptional;
64         mHideDisplayCutout = hideDisplayCutout;
65         mAppPairsOptional = appPairsOptional;
66         mMainExecutor = mainExecutor;
67     }
68 
asShellCommandHandler()69     public ShellCommandHandler asShellCommandHandler() {
70         return mImpl;
71     }
72 
73     /** Dumps WM Shell internal state. */
dump(PrintWriter pw)74     private void dump(PrintWriter pw) {
75         mShellTaskOrganizer.dump(pw, "");
76         pw.println();
77         pw.println();
78         mPipOptional.ifPresent(pip -> pip.dump(pw));
79         mLegacySplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
80         mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
81         mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
82         pw.println();
83         pw.println();
84         mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
85         pw.println();
86         pw.println();
87         mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
88     }
89 
90 
91     /** Returns {@code true} if command was found and executed. */
handleCommand(final String[] args, PrintWriter pw)92     private boolean handleCommand(final String[] args, PrintWriter pw) {
93         if (args.length < 2) {
94             // Argument at position 0 is "WMShell".
95             return false;
96         }
97         switch (args[1]) {
98             case "pair":
99                 return runPair(args, pw);
100             case "unpair":
101                 return runUnpair(args, pw);
102             case "moveToSideStage":
103                 return runMoveToSideStage(args, pw);
104             case "removeFromSideStage":
105                 return runRemoveFromSideStage(args, pw);
106             case "setSideStagePosition":
107                 return runSetSideStagePosition(args, pw);
108             case "setSideStageVisibility":
109                 return runSetSideStageVisibility(args, pw);
110             case "help":
111                 return runHelp(pw);
112             default:
113                 return false;
114         }
115     }
116 
runPair(String[] args, PrintWriter pw)117     private boolean runPair(String[] args, PrintWriter pw) {
118         if (args.length < 4) {
119             // First two arguments are "WMShell" and command name.
120             pw.println("Error: two task ids should be provided as arguments");
121             return false;
122         }
123         final int taskId1 = new Integer(args[2]);
124         final int taskId2 = new Integer(args[3]);
125         mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
126         return true;
127     }
128 
runUnpair(String[] args, PrintWriter pw)129     private boolean runUnpair(String[] args, PrintWriter pw) {
130         if (args.length < 3) {
131             // First two arguments are "WMShell" and command name.
132             pw.println("Error: task id should be provided as an argument");
133             return false;
134         }
135         final int taskId = new Integer(args[2]);
136         mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
137         return true;
138     }
139 
runMoveToSideStage(String[] args, PrintWriter pw)140     private boolean runMoveToSideStage(String[] args, PrintWriter pw) {
141         if (args.length < 3) {
142             // First arguments are "WMShell" and command name.
143             pw.println("Error: task id should be provided as arguments");
144             return false;
145         }
146         final int taskId = new Integer(args[2]);
147         final int sideStagePosition = args.length > 3
148                 ? new Integer(args[3]) : SPLIT_POSITION_BOTTOM_OR_RIGHT;
149         mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition));
150         return true;
151     }
152 
runRemoveFromSideStage(String[] args, PrintWriter pw)153     private boolean runRemoveFromSideStage(String[] args, PrintWriter pw) {
154         if (args.length < 3) {
155             // First arguments are "WMShell" and command name.
156             pw.println("Error: task id should be provided as arguments");
157             return false;
158         }
159         final int taskId = new Integer(args[2]);
160         mSplitScreenOptional.ifPresent(split -> split.removeFromSideStage(taskId));
161         return true;
162     }
163 
runSetSideStagePosition(String[] args, PrintWriter pw)164     private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
165         if (args.length < 3) {
166             // First arguments are "WMShell" and command name.
167             pw.println("Error: side stage position should be provided as arguments");
168             return false;
169         }
170         final int position = new Integer(args[2]);
171         mSplitScreenOptional.ifPresent(split -> split.setSideStagePosition(position));
172         return true;
173     }
174 
runSetSideStageVisibility(String[] args, PrintWriter pw)175     private boolean runSetSideStageVisibility(String[] args, PrintWriter pw) {
176         if (args.length < 3) {
177             // First arguments are "WMShell" and command name.
178             pw.println("Error: side stage position should be provided as arguments");
179             return false;
180         }
181         final Boolean visible = new Boolean(args[2]);
182 
183         mSplitScreenOptional.ifPresent(split -> split.setSideStageVisibility(visible));
184         return true;
185     }
186 
runHelp(PrintWriter pw)187     private boolean runHelp(PrintWriter pw) {
188         pw.println("Window Manager Shell commands:");
189         pw.println("  help");
190         pw.println("      Print this help text.");
191         pw.println("  <no arguments provided>");
192         pw.println("    Dump Window Manager Shell internal state");
193         pw.println("  pair <taskId1> <taskId2>");
194         pw.println("  unpair <taskId>");
195         pw.println("    Pairs/unpairs tasks with given ids.");
196         pw.println("  moveToSideStage <taskId> <SideStagePosition>");
197         pw.println("    Move a task with given id in split-screen mode.");
198         pw.println("  removeFromSideStage <taskId>");
199         pw.println("    Remove a task with given id in split-screen mode.");
200         pw.println("  setSideStagePosition <SideStagePosition>");
201         pw.println("    Sets the position of the side-stage.");
202         pw.println("  setSideStageVisibility <true/false>");
203         pw.println("    Show/hide side-stage.");
204         return true;
205     }
206 
207     private class HandlerImpl implements ShellCommandHandler {
208         @Override
dump(PrintWriter pw)209         public void dump(PrintWriter pw) {
210             try {
211                 mMainExecutor.executeBlocking(() -> ShellCommandHandlerImpl.this.dump(pw));
212             } catch (InterruptedException e) {
213                 throw new RuntimeException("Failed to dump the Shell in 2s", e);
214             }
215         }
216 
217         @Override
handleCommand(String[] args, PrintWriter pw)218         public boolean handleCommand(String[] args, PrintWriter pw) {
219             try {
220                 boolean[] result = new boolean[1];
221                 mMainExecutor.executeBlocking(() -> {
222                     result[0] = ShellCommandHandlerImpl.this.handleCommand(args, pw);
223                 });
224                 return result[0];
225             } catch (InterruptedException e) {
226                 throw new RuntimeException("Failed to handle Shell command in 2s", e);
227             }
228         }
229     }
230 }
231