1be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov/* 2be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** Copyright 2014, The Android Open Source Project 3be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** 4be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** Licensed under the Apache License, Version 2.0 (the "License"); 5be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** you may not use this file except in compliance with the License. 6be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** You may obtain a copy of the License at 7be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** 8be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** http://www.apache.org/licenses/LICENSE-2.0 9be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** 10be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** Unless required by applicable law or agreed to in writing, software 11be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** distributed under the License is distributed on an "AS IS" BASIS, 12be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** See the License for the specific language governing permissions and 14be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov** limitations under the License. 15be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov*/ 16be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 17be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovpackage com.android.commands.appwidget; 18be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 19be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.content.Context; 20be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.os.IBinder; 21be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.os.RemoteException; 22be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.os.ServiceManager; 23be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.os.UserHandle; 24be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport android.text.TextUtils; 25be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 26be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovimport com.android.internal.appwidget.IAppWidgetService; 27be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 28be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov/** 29be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov * This class is a command line utility for manipulating app widgets. A client 30be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov * can grant or revoke the permission for a given package to bind app widgets. 31be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov */ 32be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganovpublic class AppWidget { 33be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 34be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String USAGE = 35be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov "usage: adb shell appwidget [subcommand] [options]\n" 36be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "\n" 37be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "usage: adb shell appwidget grantbind --package <PACKAGE> " 38be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " [--user <USER_ID> | current]\n" 39be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " <PACKAGE> an Android package name.\n" 40be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " <USER_ID> The user id under which the package is installed.\n" 41be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " Example:\n" 42be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " # Grant the \"foo.bar.baz\" package to bind app widgets for the current user.\n" 43be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " adb shell grantbind --package foo.bar.baz --user current\n" 44be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "\n" 45be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "usage: adb shell appwidget revokebind --package <PACKAGE> " 46be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "[--user <USER_ID> | current]\n" 47be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " <PACKAGE> an Android package name.\n" 48be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " <USER_ID> The user id under which the package is installed.\n" 49be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " Example:\n" 50be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " # Revoke the permisison to bind app widgets from the \"foo.bar.baz\" package.\n" 51be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " adb shell revokebind --package foo.bar.baz --user current\n" 52be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + "\n"; 53be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 54be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static class Parser { 55be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String ARGUMENT_GRANT_BIND = "grantbind"; 56be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String ARGUMENT_REVOKE_BIND = "revokebind"; 57be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String ARGUMENT_PACKAGE = "--package"; 58be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String ARGUMENT_USER = "--user"; 59be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String ARGUMENT_PREFIX = "--"; 60be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static final String VALUE_USER_CURRENT = "current"; 61be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 62be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private final Tokenizer mTokenizer; 63be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 64be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public Parser(String[] args) { 65be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov mTokenizer = new Tokenizer(args); 66be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 67be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 68be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public Runnable parseCommand() { 69be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov try { 70be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov String operation = mTokenizer.nextArg(); 71be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (ARGUMENT_GRANT_BIND.equals(operation)) { 72be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return parseSetGrantBindAppWidgetPermissionCommand(true); 73be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else if (ARGUMENT_REVOKE_BIND.equals(operation)) { 74be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return parseSetGrantBindAppWidgetPermissionCommand(false); 75be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else { 76be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov throw new IllegalArgumentException("Unsupported operation: " + operation); 77be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 78be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } catch (IllegalArgumentException iae) { 79be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov System.out.println(USAGE); 80be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov System.out.println("[ERROR] " + iae.getMessage()); 81be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return null; 82be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 83be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 84be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 85be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private SetBindAppWidgetPermissionCommand parseSetGrantBindAppWidgetPermissionCommand( 86be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov boolean granted) { 87be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov String packageName = null; 88b52c7330d986e62812fd7c1b77020629e8ff7930Xiaohui Chen int userId = UserHandle.USER_SYSTEM; 89be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov for (String argument; (argument = mTokenizer.nextArg()) != null;) { 90be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (ARGUMENT_PACKAGE.equals(argument)) { 91be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov packageName = argumentValueRequired(argument); 92be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else if (ARGUMENT_USER.equals(argument)) { 93be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov String user = argumentValueRequired(argument); 94be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (VALUE_USER_CURRENT.equals(user)) { 95be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov userId = UserHandle.USER_CURRENT; 96be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else { 97be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov userId = Integer.parseInt(user); 98be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 99be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else { 100be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov throw new IllegalArgumentException("Unsupported argument: " + argument); 101be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 102be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 103be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (packageName == null) { 104be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov throw new IllegalArgumentException("Package name not specified." 105be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov + " Did you specify --package argument?"); 106be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 107be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return new SetBindAppWidgetPermissionCommand(packageName, granted, userId); 108be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 109be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 110be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private String argumentValueRequired(String argument) { 111be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov String value = mTokenizer.nextArg(); 112be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { 113be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov throw new IllegalArgumentException("No value for argument: " + argument); 114be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 115be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return value; 116be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 117be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 118be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 119be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static class Tokenizer { 120be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private final String[] mArgs; 121be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private int mNextArg; 122be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 123be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public Tokenizer(String[] args) { 124be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov mArgs = args; 125be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 126be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 127be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private String nextArg() { 128be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (mNextArg < mArgs.length) { 129be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return mArgs[mNextArg++]; 130be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } else { 131be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov return null; 132be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 133be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 134be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 135be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 136be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov private static class SetBindAppWidgetPermissionCommand implements Runnable { 137be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov final String mPackageName; 138be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov final boolean mGranted; 139be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov final int mUserId; 140be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 141be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public SetBindAppWidgetPermissionCommand(String packageName, boolean granted, 142be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov int userId) { 143be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov mPackageName = packageName; 144be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov mGranted = granted; 145be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov mUserId = userId; 146be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 147be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 148be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov @Override 149be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public void run() { 150be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov IBinder binder = ServiceManager.getService(Context.APPWIDGET_SERVICE); 151be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov IAppWidgetService appWidgetService = IAppWidgetService.Stub.asInterface(binder); 152be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov try { 15339999cf0263d0568337a87d0e586dcafd9e22ba1Svetoslav appWidgetService.setBindAppWidgetPermission(mPackageName, mUserId, mGranted); 154be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } catch (RemoteException re) { 155be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov re.printStackTrace(); 156be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 157be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 158be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 159be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov 160be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov public static void main(String[] args) { 161be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov Parser parser = new Parser(args); 162be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov Runnable command = parser.parseCommand(); 163be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov if (command != null) { 164be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov command.run(); 165be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 166be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov } 167be19c3a91a11508bd12e3355f3b1d9adf7f53194Svet Ganov} 168