1/*
2** Copyright 2014, 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
17package com.android.commands.appwidget;
18
19import android.content.Context;
20import android.os.IBinder;
21import android.os.RemoteException;
22import android.os.ServiceManager;
23import android.os.UserHandle;
24import android.text.TextUtils;
25
26import com.android.internal.appwidget.IAppWidgetService;
27
28/**
29 * This class is a command line utility for manipulating app widgets. A client
30 * can grant or revoke the permission for a given package to bind app widgets.
31 */
32public class AppWidget {
33
34    private static final String USAGE =
35        "usage: adb shell appwidget [subcommand] [options]\n"
36        + "\n"
37        + "usage: adb shell appwidget grantbind --package <PACKAGE> "
38                + " [--user <USER_ID> | current]\n"
39        + "  <PACKAGE> an Android package name.\n"
40        + "  <USER_ID> The user id under which the package is installed.\n"
41        + "  Example:\n"
42        + "  # Grant the \"foo.bar.baz\" package to bind app widgets for the current user.\n"
43        + "  adb shell grantbind --package foo.bar.baz --user current\n"
44        + "\n"
45        + "usage: adb shell appwidget revokebind --package <PACKAGE> "
46                + "[--user <USER_ID> | current]\n"
47        + "  <PACKAGE> an Android package name.\n"
48        + "  <USER_ID> The user id under which the package is installed.\n"
49        + "  Example:\n"
50        + "  # Revoke the permisison to bind app widgets from the \"foo.bar.baz\" package.\n"
51        + "  adb shell revokebind --package foo.bar.baz --user current\n"
52        + "\n";
53
54    private static class Parser {
55        private static final String ARGUMENT_GRANT_BIND = "grantbind";
56        private static final String ARGUMENT_REVOKE_BIND = "revokebind";
57        private static final String ARGUMENT_PACKAGE = "--package";
58        private static final String ARGUMENT_USER = "--user";
59        private static final String ARGUMENT_PREFIX = "--";
60        private static final String VALUE_USER_CURRENT = "current";
61
62        private final Tokenizer mTokenizer;
63
64        public Parser(String[] args) {
65            mTokenizer = new Tokenizer(args);
66        }
67
68        public Runnable parseCommand() {
69            try {
70                String operation = mTokenizer.nextArg();
71                if (ARGUMENT_GRANT_BIND.equals(operation)) {
72                    return parseSetGrantBindAppWidgetPermissionCommand(true);
73                } else if (ARGUMENT_REVOKE_BIND.equals(operation)) {
74                    return parseSetGrantBindAppWidgetPermissionCommand(false);
75                } else {
76                    throw new IllegalArgumentException("Unsupported operation: " + operation);
77                }
78            } catch (IllegalArgumentException iae) {
79                System.out.println(USAGE);
80                System.out.println("[ERROR] " + iae.getMessage());
81                return null;
82            }
83        }
84
85        private SetBindAppWidgetPermissionCommand parseSetGrantBindAppWidgetPermissionCommand(
86                boolean granted) {
87            String packageName = null;
88            int userId = UserHandle.USER_OWNER;
89            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
90                if (ARGUMENT_PACKAGE.equals(argument)) {
91                    packageName = argumentValueRequired(argument);
92                } else if (ARGUMENT_USER.equals(argument)) {
93                    String user = argumentValueRequired(argument);
94                    if (VALUE_USER_CURRENT.equals(user)) {
95                        userId = UserHandle.USER_CURRENT;
96                    } else {
97                        userId = Integer.parseInt(user);
98                    }
99                } else {
100                    throw new IllegalArgumentException("Unsupported argument: " + argument);
101                }
102            }
103            if (packageName == null) {
104                throw new IllegalArgumentException("Package name not specified."
105                        + " Did you specify --package argument?");
106            }
107            return new SetBindAppWidgetPermissionCommand(packageName, granted, userId);
108        }
109
110        private String argumentValueRequired(String argument) {
111            String value = mTokenizer.nextArg();
112            if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
113                throw new IllegalArgumentException("No value for argument: " + argument);
114            }
115            return value;
116        }
117    }
118
119    private static class Tokenizer {
120        private final String[] mArgs;
121        private int mNextArg;
122
123        public Tokenizer(String[] args) {
124            mArgs = args;
125        }
126
127        private String nextArg() {
128            if (mNextArg < mArgs.length) {
129                return mArgs[mNextArg++];
130            } else {
131                return null;
132            }
133        }
134    }
135
136    private static class SetBindAppWidgetPermissionCommand implements Runnable {
137        final String mPackageName;
138        final boolean mGranted;
139        final int mUserId;
140
141        public SetBindAppWidgetPermissionCommand(String packageName, boolean granted,
142                int userId) {
143            mPackageName = packageName;
144            mGranted = granted;
145            mUserId = userId;
146        }
147
148        @Override
149        public void run() {
150            IBinder binder = ServiceManager.getService(Context.APPWIDGET_SERVICE);
151            IAppWidgetService appWidgetService = IAppWidgetService.Stub.asInterface(binder);
152            try {
153                appWidgetService.setBindAppWidgetPermission(mPackageName, mUserId, mGranted);
154            } catch (RemoteException re) {
155                re.printStackTrace();
156            }
157        }
158    }
159
160    public static void main(String[] args) {
161        Parser parser = new Parser(args);
162        Runnable command = parser.parseCommand();
163        if (command != null) {
164            command.run();
165        }
166    }
167}
168