diff options
27 files changed, 1224 insertions, 637 deletions
diff --git a/api/current.txt b/api/current.txt index c9ef978f033f..7fe166ec8788 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24966,14 +24966,6 @@ package android.view { field public static final int ORIENTATION_UNKNOWN = -1; // 0xffffffff } - public abstract interface Overlay { - method public abstract void add(android.graphics.drawable.Drawable); - method public abstract void add(android.view.View); - method public abstract void clear(); - method public abstract void remove(android.graphics.drawable.Drawable); - method public abstract void remove(android.view.View); - } - public class ScaleGestureDetector { ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener); method public float getCurrentSpan(); @@ -25278,7 +25270,7 @@ package android.view { method public int getNextFocusUpId(); method public android.view.View.OnFocusChangeListener getOnFocusChangeListener(); method public int getOverScrollMode(); - method public android.view.Overlay getOverlay(); + method public android.view.ViewOverlay getOverlay(); method public int getPaddingBottom(); method public int getPaddingEnd(); method public int getPaddingLeft(); @@ -26019,12 +26011,23 @@ package android.view { method public abstract void onChildViewRemoved(android.view.View, android.view.View); } + public class ViewGroupOverlay extends android.view.ViewOverlay { + method public void add(android.view.View); + method public void remove(android.view.View); + } + public abstract interface ViewManager { method public abstract void addView(android.view.View, android.view.ViewGroup.LayoutParams); method public abstract void removeView(android.view.View); method public abstract void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams); } + public class ViewOverlay { + method public void add(android.graphics.drawable.Drawable); + method public void clear(); + method public void remove(android.graphics.drawable.Drawable); + } + public abstract interface ViewParent { method public abstract void bringChildToFront(android.view.View); method public abstract void childDrawableStateChanged(android.view.View); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 1c02960deeca..ccb9e1fd09b2 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -39,6 +39,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.util.AndroidException; import android.view.IWindowManager; +import com.android.internal.os.BaseCommand; import java.io.BufferedReader; import java.io.File; @@ -50,12 +51,9 @@ import java.net.URISyntaxException; import java.util.HashSet; import java.util.List; -public class Am { +public class Am extends BaseCommand { private IActivityManager mAm; - private String[] mArgs; - private int mNextArg; - private String mCurArgData; private int mStartFlags = 0; private boolean mWaitOption = false; @@ -67,33 +65,155 @@ public class Am { private String mProfileFile; - // These are magic strings understood by the Eclipse plugin. - private static final String FATAL_ERROR_CODE = "Error type 1"; - private static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; - private static final String NO_CLASS_ERROR_CODE = "Error type 3"; - /** * Command-line entry point. * * @param args The command-line arguments */ public static void main(String[] args) { - try { - (new Am()).run(args); - } catch (IllegalArgumentException e) { - showUsage(); - System.err.println("Error: " + e.getMessage()); - } catch (Exception e) { - e.printStackTrace(System.err); - System.exit(1); - } + (new Am()).run(args); } - private void run(String[] args) throws Exception { - if (args.length < 1) { - showUsage(); - return; - } + public void onShowUsage(PrintStream out) { + out.println( + "usage: am [subcommand] [options]\n" + + "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + + " [--R COUNT] [-S] [--opengl-trace]\n" + + " [--user <USER_ID> | current] <INTENT>\n" + + " am startservice [--user <USER_ID> | current] <INTENT>\n" + + " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + + " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + + " am kill-all\n" + + " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + + " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + + " [--user <USER_ID> | current]\n" + + " [--no-window-animation] <COMPONENT>\n" + + " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" + + " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + + " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + + " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + + " am clear-debug-app\n" + + " am monitor [--gdb <port>]\n" + + " am screen-compat [on|off] <PACKAGE>\n" + + " am to-uri [INTENT]\n" + + " am to-intent-uri [INTENT]\n" + + " am switch-user <USER_ID>\n" + + " am stop-user <USER_ID>\n" + + "\n" + + "am start: start an Activity. Options are:\n" + + " -D: enable debugging\n" + + " -W: wait for launch to complete\n" + + " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + + " -P <FILE>: like above, but profiling stops when app goes idle\n" + + " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + + " the top activity will be finished.\n" + + " -S: force stop the target app before starting the activity\n" + + " --opengl-trace: enable tracing of OpenGL functions\n" + + " --user <USER_ID> | current: Specify which user to run as; if not\n" + + " specified then run as the current user.\n" + + "\n" + + "am startservice: start a Service. Options are:\n" + + " --user <USER_ID> | current: Specify which user to run as; if not\n" + + " specified then run as the current user.\n" + + "\n" + + "am force-stop: force stop everything associated with <PACKAGE>.\n" + + " --user <USER_ID> | all | current: Specify user to force stop;\n" + + " all users if not specified.\n" + + "\n" + + "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + + " processes that are safe to kill -- that is, will not impact the user\n" + + " experience.\n" + + " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + + " all users if not specified.\n" + + "\n" + + "am kill-all: Kill all background processes.\n" + + "\n" + + "am broadcast: send a broadcast Intent. Options are:\n" + + " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + + " specified then send to all users.\n" + + " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + + "\n" + + "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + + " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + + " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + + " [-e perf true] to generate raw output for performance measurements.\n" + + " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + + " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + + " -p <FILE>: write profiling data to <FILE>\n" + + " -w: wait for instrumentation to finish before returning. Required for\n" + + " test runners.\n" + + " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + + " current user if not specified.\n" + + " --no-window-animation: turn off window animations will running.\n" + + "\n" + + "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + + " may be either a process name or pid. Options are:\n" + + " --user <USER_ID> | current: When supplying a process name,\n" + + " specify user of process to profile; uses current user if not specified.\n" + + "\n" + + "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + + " be either a process name or pid. Options are:\n" + + " -n: dump native heap instead of managed heap\n" + + " --user <USER_ID> | current: When supplying a process name,\n" + + " specify user of process to dump; uses current user if not specified.\n" + + "\n" + + "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + + " -w: wait for debugger when application starts\n" + + " --persistent: retain this value\n" + + "\n" + + "am clear-debug-app: clear the previously set-debug-app.\n" + + "\n" + + "am bug-report: request bug report generation; will launch UI\n" + + " when done to select where it should be delivered.\n" + + "\n" + + "am monitor: start monitoring for crashes or ANRs.\n" + + " --gdb: start gdbserv on the given port at crash/ANR\n" + + "\n" + + "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + + "\n" + + "am to-uri: print the given Intent specification as a URI.\n" + + "\n" + + "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + + "\n" + + "am switch-user: switch to put USER_ID in the foreground, starting\n" + + " execution of that user if it is currently stopped.\n" + + "\n" + + "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + + " code until a later explicit switch to it.\n" + + "\n" + + "<INTENT> specifications include these flags and arguments:\n" + + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + + " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + + " [--esn <EXTRA_KEY> ...]\n" + + " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + + " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + + " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + + " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + + " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + + " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + + " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + + " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + + " [-n <COMPONENT>] [-f <FLAGS>]\n" + + " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + + " [--debug-log-resolution] [--exclude-stopped-packages]\n" + + " [--include-stopped-packages]\n" + + " [--activity-brought-to-front] [--activity-clear-top]\n" + + " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + + " [--activity-launched-from-history] [--activity-multiple-task]\n" + + " [--activity-no-animation] [--activity-no-history]\n" + + " [--activity-no-user-action] [--activity-previous-is-top]\n" + + " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + + " [--activity-single-top] [--activity-clear-task]\n" + + " [--activity-task-on-home]\n" + + " [--receiver-registered-only] [--receiver-replace-pending]\n" + + " [--selector]\n" + + " [<URI> | <PACKAGE> | <COMPONENT>]\n" + ); + } + + public void onRun() throws Exception { mAm = ActivityManagerNative.getDefault(); if (mAm == null) { @@ -101,9 +221,7 @@ public class Am { throw new AndroidException("Can't connect to activity manager; is the system running?"); } - mArgs = args; - String op = args[0]; - mNextArg = 1; + String op = nextArgRequired(); if (op.equals("start")) { runStart(); @@ -142,7 +260,7 @@ public class Am { } else if (op.equals("stop-user")) { runStopUser(); } else { - throw new IllegalArgumentException("Unknown command: " + op); + showError("Error: unknown command '" + op + "'"); } } @@ -1303,193 +1421,4 @@ public class Am { return true; } } - - private String nextOption() { - if (mCurArgData != null) { - String prev = mArgs[mNextArg - 1]; - throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); - } - if (mNextArg >= mArgs.length) { - return null; - } - String arg = mArgs[mNextArg]; - if (!arg.startsWith("-")) { - return null; - } - mNextArg++; - if (arg.equals("--")) { - return null; - } - if (arg.length() > 1 && arg.charAt(1) != '-') { - if (arg.length() > 2) { - mCurArgData = arg.substring(2); - return arg.substring(0, 2); - } else { - mCurArgData = null; - return arg; - } - } - mCurArgData = null; - return arg; - } - - private String nextArg() { - if (mCurArgData != null) { - String arg = mCurArgData; - mCurArgData = null; - return arg; - } else if (mNextArg < mArgs.length) { - return mArgs[mNextArg++]; - } else { - return null; - } - } - - private String nextArgRequired() { - String arg = nextArg(); - if (arg == null) { - String prev = mArgs[mNextArg - 1]; - throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); - } - return arg; - } - - private static void showUsage() { - System.err.println( - "usage: am [subcommand] [options]\n" + - "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + - " [--R COUNT] [-S] [--opengl-trace]\n" + - " [--user <USER_ID> | current] <INTENT>\n" + - " am startservice [--user <USER_ID> | current] <INTENT>\n" + - " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill-all\n" + - " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + - " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + - " [--user <USER_ID> | current]\n" + - " [--no-window-animation] <COMPONENT>\n" + - " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" + - " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + - " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + - " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + - " am clear-debug-app\n" + - " am monitor [--gdb <port>]\n" + - " am screen-compat [on|off] <PACKAGE>\n" + - " am to-uri [INTENT]\n" + - " am to-intent-uri [INTENT]\n" + - " am switch-user <USER_ID>\n" + - " am stop-user <USER_ID>\n" + - "\n" + - "am start: start an Activity. Options are:\n" + - " -D: enable debugging\n" + - " -W: wait for launch to complete\n" + - " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + - " -P <FILE>: like above, but profiling stops when app goes idle\n" + - " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + - " the top activity will be finished.\n" + - " -S: force stop the target app before starting the activity\n" + - " --opengl-trace: enable tracing of OpenGL functions\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am startservice: start a Service. Options are:\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am force-stop: force stop everything associated with <PACKAGE>.\n" + - " --user <USER_ID> | all | current: Specify user to force stop;\n" + - " all users if not specified.\n" + - "\n" + - "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + - " processes that are safe to kill -- that is, will not impact the user\n" + - " experience.\n" + - " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + - " all users if not specified.\n" + - "\n" + - "am kill-all: Kill all background processes.\n" + - "\n" + - "am broadcast: send a broadcast Intent. Options are:\n" + - " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + - " specified then send to all users.\n" + - " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + - "\n" + - "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + - " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + - " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + - " [-e perf true] to generate raw output for performance measurements.\n" + - " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + - " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + - " -p <FILE>: write profiling data to <FILE>\n" + - " -w: wait for instrumentation to finish before returning. Required for\n" + - " test runners.\n" + - " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + - " current user if not specified.\n" + - " --no-window-animation: turn off window animations will running.\n" + - "\n" + - "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + - " may be either a process name or pid. Options are:\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to profile; uses current user if not specified.\n" + - "\n" + - "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + - " be either a process name or pid. Options are:\n" + - " -n: dump native heap instead of managed heap\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to dump; uses current user if not specified.\n" + - "\n" + - "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + - " -w: wait for debugger when application starts\n" + - " --persistent: retain this value\n" + - "\n" + - "am clear-debug-app: clear the previously set-debug-app.\n" + - "\n" + - "am bug-report: request bug report generation; will launch UI\n" + - " when done to select where it should be delivered.\n" + - "\n" + - "am monitor: start monitoring for crashes or ANRs.\n" + - " --gdb: start gdbserv on the given port at crash/ANR\n" + - "\n" + - "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + - "\n" + - "am to-uri: print the given Intent specification as a URI.\n" + - "\n" + - "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + - "\n" + - "am switch-user: switch to put USER_ID in the foreground, starting\n" + - " execution of that user if it is currently stopped.\n" + - "\n" + - "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + - " code until a later explicit switch to it.\n" + - "\n" + - "<INTENT> specifications include these flags and arguments:\n" + - " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + - " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + - " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + - " [--esn <EXTRA_KEY> ...]\n" + - " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + - " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + - " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + - " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + - " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + - " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + - " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + - " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + - " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + - " [-n <COMPONENT>] [-f <FLAGS>]\n" + - " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + - " [--debug-log-resolution] [--exclude-stopped-packages]\n" + - " [--include-stopped-packages]\n" + - " [--activity-brought-to-front] [--activity-clear-top]\n" + - " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + - " [--activity-launched-from-history] [--activity-multiple-task]\n" + - " [--activity-no-animation] [--activity-no-history]\n" + - " [--activity-no-user-action] [--activity-previous-is-top]\n" + - " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + - " [--activity-single-top] [--activity-clear-task]\n" + - " [--activity-task-on-home]\n" + - " [--receiver-registered-only] [--receiver-replace-pending]\n" + - " [--selector]\n" + - " [<URI> | <PACKAGE> | <COMPONENT>]\n" - ); - } } diff --git a/cmds/media/Android.mk b/cmds/media/Android.mk new file mode 100644 index 000000000000..b9451c596da0 --- /dev/null +++ b/cmds/media/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2013 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := media_cmd +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := media +LOCAL_SRC_FILES := media +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/media/MODULE_LICENSE_APACHE2 b/cmds/media/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/cmds/media/MODULE_LICENSE_APACHE2 diff --git a/cmds/media/NOTICE b/cmds/media/NOTICE new file mode 100644 index 000000000000..c5b1efa7aac7 --- /dev/null +++ b/cmds/media/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/cmds/media/media b/cmds/media/media new file mode 100755 index 000000000000..11944426b316 --- /dev/null +++ b/cmds/media/media @@ -0,0 +1,6 @@ +# Script to start "media_cmd" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/media_cmd.jar +exec app_process $base/bin com.android.commands.media.Media "$@" diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java new file mode 100644 index 000000000000..56af7d65eb35 --- /dev/null +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -0,0 +1,220 @@ +/* +** +** Copyright 2013, 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. +*/ + +package com.android.commands.media; + +import android.app.PendingIntent; +import android.content.Context; +import android.graphics.Bitmap; +import android.media.IAudioService; +import android.media.IRemoteControlDisplay; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.AndroidException; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import com.android.internal.os.BaseCommand; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; + +public class Media extends BaseCommand { + + private IAudioService mAudioService; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Media()).run(args); + } + + public void onShowUsage(PrintStream out) { + out.println( + "usage: media [subcommand] [options]\n" + + " media dispatch KEY\n" + + " media remote-display\n" + + "\n" + + "media dispatch: dispatch a media key to the current media client.\n" + + " KEY may be: play, pause, play-pause, mute, headsethook,\n" + + " stop, next, previous, rewind, recordm fast-forword.\n" + + "media remote-display: monitor remote display updates.\n" + ); + } + + public void onRun() throws Exception { + mAudioService = IAudioService.Stub.asInterface(ServiceManager.checkService( + Context.AUDIO_SERVICE)); + if (mAudioService == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to audio service; is the system running?"); + } + + String op = nextArgRequired(); + + if (op.equals("dispatch")) { + runDispatch(); + } else if (op.equals("remote-display")) { + runRemoteDisplay(); + } else { + showError("Error: unknown command '" + op + "'"); + return; + } + } + + private void sendMediaKey(KeyEvent event) { + try { + mAudioService.dispatchMediaKeyEvent(event); + } catch (RemoteException e) { + } + } + + private void runDispatch() throws Exception { + String cmd = nextArgRequired(); + int keycode; + if ("play".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PLAY; + } else if ("pause".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PAUSE; + } else if ("play-pause".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; + } else if ("mute".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MUTE; + } else if ("headsethook".equals(cmd)) { + keycode = KeyEvent.KEYCODE_HEADSETHOOK; + } else if ("stop".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_STOP; + } else if ("next".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_NEXT; + } else if ("previous".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; + } else if ("rewind".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_REWIND; + } else if ("record".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_RECORD; + } else if ("fast-forward".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; + } else { + showError("Error: unknown dispatch code '" + cmd + "'"); + return; + } + + final long now = SystemClock.uptimeMillis(); + sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + } + + class RemoteDisplayMonitor extends IRemoteControlDisplay.Stub { + RemoteDisplayMonitor() { + } + + + @Override + public void setCurrentClientId(int clientGeneration, PendingIntent clientMediaIntent, + boolean clearing) { + System.out.println("New client: id=" + clientGeneration + + " intent=" + clientMediaIntent + " clearing=" + clearing); + } + + @Override + public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, + long currentPosMs, float speed) { + System.out.println("New state: id=" + generationId + " state=" + state + + " time=" + stateChangeTimeMs + " pos=" + currentPosMs + " speed=" + speed); + } + + @Override + public void setTransportControlInfo(int generationId, int transportControlFlags, + int posCapabilities) { + System.out.println("New control info: id=" + generationId + + " flags=0x" + Integer.toHexString(transportControlFlags) + + " cap=0x" + Integer.toHexString(posCapabilities)); + } + + @Override + public void setMetadata(int generationId, Bundle metadata) { + System.out.println("New metadata: id=" + generationId + + " data=" + metadata); + } + + @Override + public void setArtwork(int generationId, Bitmap artwork) { + System.out.println("New artwork: id=" + generationId + + " art=" + artwork); + } + + @Override + public void setAllMetadata(int generationId, Bundle metadata, Bitmap artwork) { + System.out.println("New metadata+artwork: id=" + generationId + + " data=" + metadata + " art=" + artwork); + } + + void printUsageMessage() { + System.out.println("Monitoring remote control displays... available commands:"); + System.out.println("(q)uit: finish monitoring"); + } + + void run() throws RemoteException { + printUsageMessage(); + + mAudioService.registerRemoteControlDisplay(this, 0, 0); + + try { + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + String line; + + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + break; + } else { + System.out.println("Invalid command: " + line); + } + + synchronized (this) { + if (addNewline) { + System.out.println(""); + } + printUsageMessage(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + mAudioService.unregisterRemoteControlDisplay(this); + } + } + } + + private void runRemoteDisplay() throws Exception { + RemoteDisplayMonitor monitor = new RemoteDisplayMonitor(); + monitor.run(); + } +} diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java index 31eba96f7056..815a0ac999eb 100644 --- a/cmds/wm/src/com/android/commands/wm/Wm.java +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -26,21 +26,15 @@ import android.os.ServiceManager; import android.util.AndroidException; import android.view.Display; import android.view.IWindowManager; +import com.android.internal.os.BaseCommand; +import java.io.PrintStream; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Wm { +public class Wm extends BaseCommand { private IWindowManager mWm; - private String[] mArgs; - private int mNextArg; - private String mCurArgData; - - // These are magic strings understood by the Eclipse plugin. - private static final String FATAL_ERROR_CODE = "Error type 1"; - private static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; - private static final String NO_CLASS_ERROR_CODE = "Error type 3"; /** * Command-line entry point. @@ -48,23 +42,25 @@ public class Wm { * @param args The command-line arguments */ public static void main(String[] args) { - try { - (new Wm()).run(args); - } catch (IllegalArgumentException e) { - showUsage(); - System.err.println("Error: " + e.getMessage()); - } catch (Exception e) { - e.printStackTrace(System.err); - System.exit(1); - } + (new Wm()).run(args); } - private void run(String[] args) throws Exception { - if (args.length < 1) { - showUsage(); - return; - } + public void onShowUsage(PrintStream out) { + out.println( + "usage: wm [subcommand] [options]\n" + + " wm size [reset|WxH]\n" + + " wm density [reset|DENSITY]\n" + + " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + + "\n" + + "wm size: return or override display size.\n" + + "\n" + + "wm density: override display density.\n" + + "\n" + + "wm overscan: set overscan area for display.\n" + ); + } + public void onRun() throws Exception { mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService( Context.WINDOW_SERVICE)); if (mWm == null) { @@ -72,9 +68,7 @@ public class Wm { throw new AndroidException("Can't connect to window manager; is the system running?"); } - mArgs = args; - String op = args[0]; - mNextArg = 1; + String op = nextArgRequired(); if (op.equals("size")) { runDisplaySize(); @@ -83,7 +77,8 @@ public class Wm { } else if (op.equals("overscan")) { runDisplayOverscan(); } else { - throw new IllegalArgumentException("Unknown command: " + op); + showError("Error: unknown command '" + op + "'"); + return; } } @@ -198,69 +193,4 @@ public class Wm { } catch (RemoteException e) { } } - - private String nextOption() { - if (mCurArgData != null) { - String prev = mArgs[mNextArg - 1]; - throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); - } - if (mNextArg >= mArgs.length) { - return null; - } - String arg = mArgs[mNextArg]; - if (!arg.startsWith("-")) { - return null; - } - mNextArg++; - if (arg.equals("--")) { - return null; - } - if (arg.length() > 1 && arg.charAt(1) != '-') { - if (arg.length() > 2) { - mCurArgData = arg.substring(2); - return arg.substring(0, 2); - } else { - mCurArgData = null; - return arg; - } - } - mCurArgData = null; - return arg; - } - - private String nextArg() { - if (mCurArgData != null) { - String arg = mCurArgData; - mCurArgData = null; - return arg; - } else if (mNextArg < mArgs.length) { - return mArgs[mNextArg++]; - } else { - return null; - } - } - - private String nextArgRequired() { - String arg = nextArg(); - if (arg == null) { - String prev = mArgs[mNextArg - 1]; - throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); - } - return arg; - } - - private static void showUsage() { - System.err.println( - "usage: wm [subcommand] [options]\n" + - " wm size [reset|WxH]\n" + - " wm density [reset|DENSITY]\n" + - " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + - "\n" + - "wm size: return or override display size.\n" + - "\n" + - "wm density: override display density.\n" + - "\n" + - "wm overscan: set overscan area for display.\n" - ); - } } diff --git a/core/java/android/animation/RectEvaluator.java b/core/java/android/animation/RectEvaluator.java index 10932bbddf07..28d496b346f0 100644 --- a/core/java/android/animation/RectEvaluator.java +++ b/core/java/android/animation/RectEvaluator.java @@ -18,7 +18,7 @@ package android.animation; import android.graphics.Rect; /** - * This evaluator can be used to perform type interpolation between <code>int</code> values. + * This evaluator can be used to perform type interpolation between <code>Rect</code> values. */ public class RectEvaluator implements TypeEvaluator<Rect> { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index ebca04147d22..a7543a83f1b2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1603,7 +1603,7 @@ public class Notification implements Parcelable n.defaults = mDefaults; n.flags = mFlags; n.bigContentView = makeBigContentView(); - if (mLedOnMs != 0 && mLedOffMs != 0) { + if (mLedOnMs != 0 || mLedOffMs != 0) { n.flags |= FLAG_SHOW_LIGHTS; } if ((mDefaults & DEFAULT_LIGHTS) != 0) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3b06da7120ec..a520e173a7da 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12107,7 +12107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, //System.out.println("Attached! " + this); mAttachInfo = info; if (mOverlay != null) { - mOverlay.dispatchAttachedToWindow(info, visibility); + mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); } mWindowAttachCount++; // We will need to evaluate the drawable state at least once. @@ -12178,7 +12178,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo = null; if (mOverlay != null) { - mOverlay.dispatchDetachedFromWindow(); + mOverlay.getOverlayView().dispatchDetachedFromWindow(); } } @@ -12831,7 +12831,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { dispatchDraw(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { - mOverlay.draw(canvas); + mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); @@ -13147,7 +13147,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchDraw(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { - mOverlay.draw(canvas); + mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); @@ -13905,7 +13905,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDrawScrollBars(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { - mOverlay.dispatchDraw(canvas); + mOverlay.getOverlayView().dispatchDraw(canvas); } // we're done... @@ -14049,34 +14049,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDrawScrollBars(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { - mOverlay.dispatchDraw(canvas); + mOverlay.getOverlayView().dispatchDraw(canvas); } } /** - * Called by the addToOverlay() methods to create, attach, and size the overlay as necessary + * Returns the overlay for this view, creating it if it does not yet exist. + * Adding drawables to the overlay will cause them to be displayed whenever + * the view itself is redrawn. Objects in the overlay should be actively + * managed: remove them when they should not be displayed anymore. The + * overlay will always have the same size as its host view. + * + * @return The ViewOverlay object for this view. + * @see ViewOverlay */ - private void setupOverlay() { + public ViewOverlay getOverlay() { if (mOverlay == null) { mOverlay = new ViewOverlay(mContext, this); - mOverlay.mAttachInfo = mAttachInfo; - mOverlay.setRight(mRight); - mOverlay.setBottom(mBottom); } - } - - /** - * Returns the overlay for this view, creating it if it does not yet exist. Adding drawables - * and/or views to the overlay will cause them to be displayed whenever the view itself is - * redrawn. Objects in the overlay should be actively managed: remove them when they should - * not be displayed anymore and invalidate this view appropriately when overlay drawables - * change. The overlay will always have the same size as its host view. - * - * @return The Overlay object for this view. - * @see Overlay - */ - public Overlay getOverlay() { - setupOverlay(); return mOverlay; } @@ -14360,8 +14350,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); if (mOverlay != null) { - mOverlay.setRight(mRight); - mOverlay.setBottom(mBottom); + mOverlay.getOverlayView().setRight(newWidth); + mOverlay.getOverlayView().setBottom(newHeight); } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index f615e1bcf48f..c07191ae5bdc 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1876,34 +1876,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // have become out of sync. removePointersFromTouchTargets(idBitsToAssign); - final float x = ev.getX(actionIndex); - final float y = ev.getY(actionIndex); - - if (mOverlay != null) { - ViewOverlay overlay = (ViewOverlay) mOverlay; - // Check to see whether the overlay can handle the event - final View child = mOverlay; - if (canViewReceivePointerEvents(child) && - isTransformedTouchPointInView(x, y, child, null)) { - newTouchTarget = getTouchTarget(child); - if (newTouchTarget != null) { - newTouchTarget.pointerIdBits |= idBitsToAssign; - } else { - resetCancelNextUpFlag(child); - if (dispatchTransformedTouchEvent(ev, false, child, - idBitsToAssign)) { - mLastTouchDownTime = ev.getDownTime(); - mLastTouchDownX = ev.getX(); - mLastTouchDownY = ev.getY(); - newTouchTarget = addTouchTarget(child, idBitsToAssign); - alreadyDispatchedToNewTouchTarget = true; - } - } - } - } - final int childrenCount = mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. final View[] children = mChildren; @@ -2991,6 +2967,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * Returns the ViewGroupOverlay for this view group, creating it if it does + * not yet exist. In addition to {@link ViewOverlay}'s support for drawables, + * {@link ViewGroupOverlay} allows views to be added to the overlay. These + * views, like overlay drawables, are visual-only; they do not receive input + * events and should not be used as anything other than a temporary + * representation of a view in a parent container, such as might be used + * by an animation effect. + * + * @return The ViewGroupOverlay object for this view. + * @see ViewGroupOverlay + */ + @Override + public ViewGroupOverlay getOverlay() { + if (mOverlay == null) { + mOverlay = new ViewGroupOverlay(mContext, this); + } + return (ViewGroupOverlay) mOverlay; + } + + /** * Returns the index of the child to draw for this iteration. Override this * if you want to change the drawing order of children. By default, it * returns i. @@ -3055,11 +3051,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } if (mOverlay != null) { - mOverlay.mRecreateDisplayList = (mOverlay.mPrivateFlags & PFLAG_INVALIDATED) + View overlayView = mOverlay.getOverlayView(); + overlayView.mRecreateDisplayList = (overlayView.mPrivateFlags & PFLAG_INVALIDATED) == PFLAG_INVALIDATED; - mOverlay.mPrivateFlags &= ~PFLAG_INVALIDATED; - mOverlay.getDisplayList(); - mOverlay.mRecreateDisplayList = false; + overlayView.mPrivateFlags &= ~PFLAG_INVALIDATED; + overlayView.getDisplayList(); + overlayView.mRecreateDisplayList = false; } } diff --git a/core/java/android/view/Overlay.java b/core/java/android/view/ViewGroupOverlay.java index 66307529e224..c1b24f26503c 100644 --- a/core/java/android/view/Overlay.java +++ b/core/java/android/view/ViewGroupOverlay.java @@ -15,43 +15,37 @@ */ package android.view; +import android.content.Context; import android.graphics.drawable.Drawable; /** - * An overlay is an extra layer that sits on top of a View (the "host view") - * which is drawn after all other content in that view (including children, - * if the view is a ViewGroup). Interaction with the overlay layer is done in - * terms of adding/removing views and drawables. + * A group overlay is an extra layer that sits on top of a ViewGroup + * (the "host view") which is drawn after all other content in that view + * (including the view group's children). Interaction with the overlay + * layer is done by adding and removing views and drawables. * - * @see android.view.View#getOverlay() + * <p>ViewGroupOverlay is a subclass of {@link ViewOverlay}, adding the ability to + * manage views for overlays on ViewGroups, in addition to the drawable + * support in ViewOverlay.</p> + * + * @see ViewGroup#getOverlay() */ -public interface Overlay { +public class ViewGroupOverlay extends ViewOverlay { - /** - * Adds a Drawable to the overlay. The bounds of the drawable should be relative to - * the host view. Any drawable added to the overlay should be removed when it is no longer - * needed or no longer visible. - * - * @param drawable The Drawable to be added to the overlay. This drawable will be - * drawn when the view redraws its overlay. - * @see #remove(android.graphics.drawable.Drawable) - * @see #add(View) - */ - void add(Drawable drawable); - - /** - * Removes the specified Drawable from the overlay. - * - * @param drawable The Drawable to be removed from the overlay. - * @see #add(android.graphics.drawable.Drawable) - */ - void remove(Drawable drawable); + ViewGroupOverlay(Context context, View hostView) { + super(context, hostView); + } /** * Adds a View to the overlay. The bounds of the added view should be * relative to the host view. Any view added to the overlay should be * removed when it is no longer needed or no longer visible. * + * <p>Views in the overlay are visual-only; they do not receive input + * events and do not participate in focus traversal. Overlay views + * are intended to be transient, such as might be needed by a temporary + * animation effect.</p> + * * <p>If the view has a parent, the view will be removed from that parent * before being added to the overlay. Also, the view will be repositioned * such that it is in the same relative location inside the activity. For @@ -62,20 +56,20 @@ public interface Overlay { * @param view The View to be added to the overlay. The added view will be * drawn when the overlay is drawn. * @see #remove(View) - * @see #add(android.graphics.drawable.Drawable) + * @see ViewOverlay#add(Drawable) */ - void add(View view); + public void add(View view) { + mOverlayViewGroup.add(view); + } /** * Removes the specified View from the overlay. * * @param view The View to be removed from the overlay. * @see #add(View) + * @see ViewOverlay#remove(Drawable) */ - void remove(View view); - - /** - * Removes all views and drawables from the overlay. - */ - void clear(); + public void remove(View view) { + mOverlayViewGroup.remove(view); + } } diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java index 8b18d53b7ee1..78e2597d728c 100644 --- a/core/java/android/view/ViewOverlay.java +++ b/core/java/android/view/ViewOverlay.java @@ -23,215 +23,286 @@ import android.graphics.drawable.Drawable; import java.util.ArrayList; /** - * ViewOverlay is a container that View uses to host all objects (views and - * drawables) that are added to its "overlay", gotten through - * {@link View#getOverlay()}. Views and drawables are added to the overlay - * via the add/remove methods in this class. These views and drawables are - * drawn whenever the view itself is drawn; first the view draws its own - * content (and children, if it is a ViewGroup), then it draws its overlay - * (if it has one). + * An overlay is an extra layer that sits on top of a View (the "host view") + * which is drawn after all other content in that view (including children, + * if the view is a ViewGroup). Interaction with the overlay layer is done + * by adding and removing drawables. * - * Besides managing and drawing the list of drawables, this class serves - * two purposes: - * (1) it noops layout calls because children are absolutely positioned and - * (2) it forwards all invalidation calls to its host view. The invalidation - * redirect is necessary because the overlay is not a child of the host view - * and invalidation cannot therefore follow the normal path up through the - * parent hierarchy. + * <p>An overlay requested from a ViewGroup is of type {@link ViewGroupOverlay}, + * which also supports adding and removing views.</p> * - * @hide + * @see View#getOverlay() View.getOverlay() + * @see ViewGroup#getOverlay() ViewGroup.getOverlay() + * @see ViewGroupOverlay */ -class ViewOverlay extends ViewGroup implements Overlay { +public class ViewOverlay { /** - * The View for which this is an overlay. Invalidations of the overlay are redirected to - * this host view. + * The actual container for the drawables (and views, if it's a ViewGroupOverlay). + * All of the management and rendering details for the overlay are handled in + * OverlayViewGroup. */ - View mHostView; + OverlayViewGroup mOverlayViewGroup; + + ViewOverlay(Context context, View hostView) { + mOverlayViewGroup = new OverlayViewGroup(context, hostView); + } /** - * The set of drawables to draw when the overlay is rendered. + * Used internally by View and ViewGroup to handle drawing and invalidation + * of the overlay + * @return */ - ArrayList<Drawable> mDrawables = null; - - ViewOverlay(Context context, View host) { - super(context); - mHostView = host; - mParent = mHostView.getParent(); + ViewGroup getOverlayView() { + return mOverlayViewGroup; } - @Override + /** + * Adds a Drawable to the overlay. The bounds of the drawable should be relative to + * the host view. Any drawable added to the overlay should be removed when it is no longer + * needed or no longer visible. + * + * @param drawable The Drawable to be added to the overlay. This drawable will be + * drawn when the view redraws its overlay. + * @see #remove(Drawable) + */ public void add(Drawable drawable) { - if (mDrawables == null) { - mDrawables = new ArrayList<Drawable>(); - } - if (!mDrawables.contains(drawable)) { - // Make each drawable unique in the overlay; can't add it more than once - mDrawables.add(drawable); - invalidate(drawable.getBounds()); - drawable.setCallback(this); - } + mOverlayViewGroup.add(drawable); } - @Override + /** + * Removes the specified Drawable from the overlay. + * + * @param drawable The Drawable to be removed from the overlay. + * @see #add(Drawable) + */ public void remove(Drawable drawable) { - if (mDrawables != null) { - mDrawables.remove(drawable); - invalidate(drawable.getBounds()); - drawable.setCallback(null); - } + mOverlayViewGroup.remove(drawable); } - @Override - public void invalidateDrawable(Drawable drawable) { - invalidate(drawable.getBounds()); + /** + * Removes all content from the overlay. + */ + public void clear() { + mOverlayViewGroup.clear(); } - @Override - public void add(View child) { - int deltaX = 0; - int deltaY = 0; - if (child.getParent() instanceof ViewGroup) { - ViewGroup parent = (ViewGroup) child.getParent(); - if (parent != mHostView) { - // Moving to different container; figure out how to position child such that - // it is in the same location on the screen - int[] parentLocation = new int[2]; - int[] hostViewLocation = new int[2]; - parent.getLocationOnScreen(parentLocation); - mHostView.getLocationOnScreen(hostViewLocation); - child.offsetLeftAndRight(parentLocation[0] - hostViewLocation[0]); - child.offsetTopAndBottom(parentLocation[1] - hostViewLocation[1]); + boolean isEmpty() { + return mOverlayViewGroup.isEmpty(); + } + + /** + * OverlayViewGroup is a container that View and ViewGroup use to host + * drawables and views added to their overlays ({@link ViewOverlay} and + * {@link ViewGroupOverlay}, respectively). Drawables are added to the overlay + * via the add/remove methods in ViewOverlay, Views are added/removed via + * ViewGroupOverlay. These drawable and view objects are + * drawn whenever the view itself is drawn; first the view draws its own + * content (and children, if it is a ViewGroup), then it draws its overlay + * (if it has one). + * + * <p>Besides managing and drawing the list of drawables, this class serves + * two purposes: + * (1) it noops layout calls because children are absolutely positioned and + * (2) it forwards all invalidation calls to its host view. The invalidation + * redirect is necessary because the overlay is not a child of the host view + * and invalidation cannot therefore follow the normal path up through the + * parent hierarchy.</p> + * + * @see View#getOverlay() + * @see ViewGroup#getOverlay() + */ + static class OverlayViewGroup extends ViewGroup { + + /** + * The View for which this is an overlay. Invalidations of the overlay are redirected to + * this host view. + */ + View mHostView; + + /** + * The set of drawables to draw when the overlay is rendered. + */ + ArrayList<Drawable> mDrawables = null; + + OverlayViewGroup(Context context, View hostView) { + super(context); + mHostView = hostView; + mAttachInfo = mHostView.mAttachInfo; + mRight = hostView.getWidth(); + mBottom = hostView.getHeight(); + } + + public void add(Drawable drawable) { + if (mDrawables == null) { + + mDrawables = new ArrayList<Drawable>(); + } + if (!mDrawables.contains(drawable)) { + // Make each drawable unique in the overlay; can't add it more than once + mDrawables.add(drawable); + invalidate(drawable.getBounds()); + drawable.setCallback(this); } - parent.removeView(child); } - super.addView(child); - } - @Override - public void remove(View view) { - super.removeView(view); - } + public void remove(Drawable drawable) { + if (mDrawables != null) { + mDrawables.remove(drawable); + invalidate(drawable.getBounds()); + drawable.setCallback(null); + } + } - @Override - public void clear() { - removeAllViews(); - mDrawables.clear(); - } + public void add(View child) { + if (child.getParent() instanceof ViewGroup) { + ViewGroup parent = (ViewGroup) child.getParent(); + if (parent != mHostView) { + // Moving to different container; figure out how to position child such that + // it is in the same location on the screen + int[] parentLocation = new int[2]; + int[] hostViewLocation = new int[2]; + parent.getLocationOnScreen(parentLocation); + mHostView.getLocationOnScreen(hostViewLocation); + child.offsetLeftAndRight(parentLocation[0] - hostViewLocation[0]); + child.offsetTopAndBottom(parentLocation[1] - hostViewLocation[1]); + } + parent.removeView(child); + } + super.addView(child); + } - boolean isEmpty() { - if (getChildCount() == 0 && (mDrawables == null || mDrawables.size() == 0)) { - return true; + public void remove(View view) { + super.removeView(view); } - return false; - } - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - final int numDrawables = (mDrawables == null) ? 0 : mDrawables.size(); - for (int i = 0; i < numDrawables; ++i) { - mDrawables.get(i).draw(canvas); + public void clear() { + removeAllViews(); + mDrawables.clear(); } - } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Noop: children are positioned absolutely - } + boolean isEmpty() { + if (getChildCount() == 0 && + (mDrawables == null || mDrawables.size() == 0)) { + return true; + } + return false; + } - /* - The following invalidation overrides exist for the purpose of redirecting invalidation to - the host view. The overlay is not parented to the host view (since a View cannot be a parent), - so the invalidation cannot proceed through the normal parent hierarchy. - There is a built-in assumption that the overlay exactly covers the host view, therefore - the invalidation rectangles received do not need to be adjusted when forwarded to - the host view. - */ + @Override + public void invalidateDrawable(Drawable drawable) { + invalidate(drawable.getBounds()); + } - @Override - public void invalidate(Rect dirty) { - super.invalidate(dirty); - if (mHostView != null) { - mHostView.invalidate(dirty); + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + final int numDrawables = (mDrawables == null) ? 0 : mDrawables.size(); + for (int i = 0; i < numDrawables; ++i) { + mDrawables.get(i).draw(canvas); + } } - } - @Override - public void invalidate(int l, int t, int r, int b) { - super.invalidate(l, t, r, b); - if (mHostView != null) { - mHostView.invalidate(l, t, r, b); + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + // Noop: children are positioned absolutely } - } - @Override - public void invalidate() { - super.invalidate(); - if (mHostView != null) { - mHostView.invalidate(); + /* + The following invalidation overrides exist for the purpose of redirecting invalidation to + the host view. The overlay is not parented to the host view (since a View cannot be a + parent), so the invalidation cannot proceed through the normal parent hierarchy. + There is a built-in assumption that the overlay exactly covers the host view, therefore + the invalidation rectangles received do not need to be adjusted when forwarded to + the host view. + */ + + @Override + public void invalidate(Rect dirty) { + super.invalidate(dirty); + if (mHostView != null) { + mHostView.invalidate(dirty); + } } - } - @Override - void invalidate(boolean invalidateCache) { - super.invalidate(invalidateCache); - if (mHostView != null) { - mHostView.invalidate(invalidateCache); + @Override + public void invalidate(int l, int t, int r, int b) { + super.invalidate(l, t, r, b); + if (mHostView != null) { + mHostView.invalidate(l, t, r, b); + } } - } - @Override - void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { - super.invalidateViewProperty(invalidateParent, forceRedraw); - if (mHostView != null) { - mHostView.invalidateViewProperty(invalidateParent, forceRedraw); + @Override + public void invalidate() { + super.invalidate(); + if (mHostView != null) { + mHostView.invalidate(); + } } - } - @Override - protected void invalidateParentCaches() { - super.invalidateParentCaches(); - if (mHostView != null) { - mHostView.invalidateParentCaches(); + @Override + void invalidate(boolean invalidateCache) { + super.invalidate(invalidateCache); + if (mHostView != null) { + mHostView.invalidate(invalidateCache); + } } - } - @Override - protected void invalidateParentIfNeeded() { - super.invalidateParentIfNeeded(); - if (mHostView != null) { - mHostView.invalidateParentIfNeeded(); + @Override + void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { + super.invalidateViewProperty(invalidateParent, forceRedraw); + if (mHostView != null) { + mHostView.invalidateViewProperty(invalidateParent, forceRedraw); + } } - } - public void invalidateChildFast(View child, final Rect dirty) { - if (mHostView != null) { - // Note: This is not a "fast" invalidation. Would be nice to instead invalidate using DL - // properties and a dirty rect instead of causing a real invalidation of the host view - int left = child.mLeft; - int top = child.mTop; - if (!child.getMatrix().isIdentity()) { - child.transformRect(dirty); + @Override + protected void invalidateParentCaches() { + super.invalidateParentCaches(); + if (mHostView != null) { + mHostView.invalidateParentCaches(); + } + } + + @Override + protected void invalidateParentIfNeeded() { + super.invalidateParentIfNeeded(); + if (mHostView != null) { + mHostView.invalidateParentIfNeeded(); } - dirty.offset(left, top); - mHostView.invalidate(dirty); } - } - @Override - public ViewParent invalidateChildInParent(int[] location, Rect dirty) { - if (mHostView != null) { - dirty.offset(location[0], location[1]); - if (mHostView instanceof ViewGroup) { - location[0] = 0; - location[1] = 0; - super.invalidateChildInParent(location, dirty); - return ((ViewGroup) mHostView).invalidateChildInParent(location, dirty); - } else { - invalidate(dirty); + public void invalidateChildFast(View child, final Rect dirty) { + if (mHostView != null) { + // Note: This is not a "fast" invalidation. Would be nice to instead invalidate + // using DisplayList properties and a dirty rect instead of causing a real + // invalidation of the host view + int left = child.mLeft; + int top = child.mTop; + if (!child.getMatrix().isIdentity()) { + child.transformRect(dirty); + } + dirty.offset(left, top); + mHostView.invalidate(dirty); } } - return null; + + @Override + public ViewParent invalidateChildInParent(int[] location, Rect dirty) { + if (mHostView != null) { + dirty.offset(location[0], location[1]); + if (mHostView instanceof ViewGroup) { + location[0] = 0; + location[1] = 0; + super.invalidateChildInParent(location, dirty); + return ((ViewGroup) mHostView).invalidateChildInParent(location, dirty); + } else { + invalidate(dirty); + } + } + return null; + } } + } diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java index 684ec073ce45..17eb2df2ffc7 100644 --- a/core/java/android/webkit/HTML5Audio.java +++ b/core/java/android/webkit/HTML5Audio.java @@ -19,6 +19,7 @@ package android.webkit; import android.content.Context; import android.media.AudioManager; import android.media.MediaPlayer; +import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -84,6 +85,7 @@ class HTML5Audio extends Handler // See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate private Timer mTimer; private final class TimeupdateTask extends TimerTask { + @Override public void run() { HTML5Audio.this.obtainMessage(TIMEUPDATE).sendToTarget(); } @@ -139,11 +141,13 @@ class HTML5Audio extends Handler // (i.e. the webviewcore thread here) // MediaPlayer.OnBufferingUpdateListener + @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { nativeOnBuffering(percent, mNativePointer); } // MediaPlayer.OnCompletionListener; + @Override public void onCompletion(MediaPlayer mp) { mState = COMPLETE; mProcessingOnEnd = true; @@ -156,6 +160,7 @@ class HTML5Audio extends Handler } // MediaPlayer.OnErrorListener + @Override public boolean onError(MediaPlayer mp, int what, int extra) { mState = ERROR; resetMediaPlayer(); @@ -164,6 +169,7 @@ class HTML5Audio extends Handler } // MediaPlayer.OnPreparedListener + @Override public void onPrepared(MediaPlayer mp) { mState = PREPARED; if (mTimer != null) { @@ -178,6 +184,7 @@ class HTML5Audio extends Handler } // MediaPlayer.OnSeekCompleteListener + @Override public void onSeekComplete(MediaPlayer mp) { nativeOnTimeupdate(mp.getCurrentPosition(), mNativePointer); } @@ -231,7 +238,7 @@ class HTML5Audio extends Handler headers.put(HIDE_URL_LOGS, "true"); } - mMediaPlayer.setDataSource(url, headers); + mMediaPlayer.setDataSource(mContext, Uri.parse(url), headers); mState = INITIALIZED; mMediaPlayer.prepareAsync(); } catch (IOException e) { diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index 589a358af59b..34cfea546e7a 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -244,11 +244,11 @@ public class AppSecurityPermissions { public void onClick(DialogInterface dialog, int which) { PackageManager pm = getContext().getPackageManager(); pm.revokePermission(mPackageName, mPerm.name); - PermissionItemView.this.setVisibility(View.INVISIBLE); + PermissionItemView.this.setVisibility(View.GONE); } }; - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.revoke, ocl); + builder.setNegativeButton(R.string.revoke, ocl); + builder.setPositiveButton(R.string.ok, null); } } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 529de2e24b04..3df7258ba44c 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -220,28 +220,29 @@ public class RelativeLayout extends ViewGroup { // with MeasureSpec value overflow and RelativeLayout was one source of them. // Some apps came to rely on them. :( private boolean mAllowBrokenMeasureSpecs = false; + // Compatibility hack. Old versions of the platform would not take + // margins and padding into account when generating the height measure spec + // for children during the horizontal measure pass. + private boolean mMeasureVerticalWithPaddingMargin = false; // A default width used for RTL measure pass - private static int DEFAULT_WIDTH = Integer.MAX_VALUE / 2; + private static final int DEFAULT_WIDTH = Integer.MAX_VALUE / 2; public RelativeLayout(Context context) { super(context); - mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= - Build.VERSION_CODES.JELLY_BEAN_MR1; + queryCompatibilityModes(context); } public RelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); initFromAttributes(context, attrs); - mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= - Build.VERSION_CODES.JELLY_BEAN_MR1; + queryCompatibilityModes(context); } public RelativeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initFromAttributes(context, attrs); - mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <= - Build.VERSION_CODES.JELLY_BEAN_MR1; + queryCompatibilityModes(context); } private void initFromAttributes(Context context, AttributeSet attrs) { @@ -251,6 +252,12 @@ public class RelativeLayout extends ViewGroup { a.recycle(); } + private void queryCompatibilityModes(Context context) { + int version = context.getApplicationInfo().targetSdkVersion; + mAllowBrokenMeasureSpecs = version <= Build.VERSION_CODES.JELLY_BEAN_MR1; + mMeasureVerticalWithPaddingMargin = version >= Build.VERSION_CODES.JELLY_BEAN_MR2; + } + @Override public boolean shouldDelayChildPressedState() { return false; @@ -692,6 +699,11 @@ public class RelativeLayout extends ViewGroup { params.leftMargin, params.rightMargin, mPaddingLeft, mPaddingRight, myWidth); + int maxHeight = myHeight; + if (mMeasureVerticalWithPaddingMargin) { + maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom - + params.topMargin - params.bottomMargin); + } int childHeightMeasureSpec; if (myHeight < 0 && !mAllowBrokenMeasureSpecs) { if (params.height >= 0) { @@ -704,9 +716,9 @@ public class RelativeLayout extends ViewGroup { childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } } else if (params.width == LayoutParams.MATCH_PARENT) { - childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.EXACTLY); + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY); } else { - childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.AT_MOST); + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST); } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java new file mode 100644 index 000000000000..e26b27d5820c --- /dev/null +++ b/core/java/com/android/internal/os/BaseCommand.java @@ -0,0 +1,146 @@ +/* +** +** Copyright 2013, 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. +*/ + +package com.android.internal.os; + +import java.io.PrintStream; + +public abstract class BaseCommand { + + protected String[] mArgs; + private int mNextArg; + private String mCurArgData; + + // These are magic strings understood by the Eclipse plugin. + public static final String FATAL_ERROR_CODE = "Error type 1"; + public static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; + public static final String NO_CLASS_ERROR_CODE = "Error type 3"; + + /** + * Call to run the command. + */ + public void run(String[] args) { + if (args.length < 1) { + onShowUsage(System.out); + return; + } + + mArgs = args; + mNextArg = 0; + mCurArgData = null; + + try { + onRun(); + } catch (IllegalArgumentException e) { + onShowUsage(System.err); + System.err.println(); + System.err.println("Error: " + e.getMessage()); + } catch (Exception e) { + e.printStackTrace(System.err); + System.exit(1); + } + } + + /** + * Convenience to show usage information to error output. + */ + public void showUsage() { + onShowUsage(System.err); + } + + /** + * Convenience to show usage information to error output along + * with an error message. + */ + public void showError(String message) { + onShowUsage(System.err); + System.err.println(); + System.err.println(message); + } + + /** + * Implement the command. + */ + public abstract void onRun() throws Exception; + + /** + * Print help text for the command. + */ + public abstract void onShowUsage(PrintStream out); + + /** + * Return the next option on the command line -- that is an argument that + * starts with '-'. If the next argument is not an option, null is returned. + */ + public String nextOption() { + if (mCurArgData != null) { + String prev = mArgs[mNextArg - 1]; + throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); + } + if (mNextArg >= mArgs.length) { + return null; + } + String arg = mArgs[mNextArg]; + if (!arg.startsWith("-")) { + return null; + } + mNextArg++; + if (arg.equals("--")) { + return null; + } + if (arg.length() > 1 && arg.charAt(1) != '-') { + if (arg.length() > 2) { + mCurArgData = arg.substring(2); + return arg.substring(0, 2); + } else { + mCurArgData = null; + return arg; + } + } + mCurArgData = null; + return arg; + } + + /** + * Return the next argument on the command line, whatever it is; if there are + * no arguments left, return null. + */ + public String nextArg() { + if (mCurArgData != null) { + String arg = mCurArgData; + mCurArgData = null; + return arg; + } else if (mNextArg < mArgs.length) { + return mArgs[mNextArg++]; + } else { + return null; + } + } + + /** + * Return the next argument on the command line, whatever it is; if there are + * no arguments left, throws an IllegalArgumentException to report this to the user. + */ + public String nextArgRequired() { + String arg = nextArg(); + if (arg == null) { + String prev = mArgs[mNextArg - 1]; + throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); + } + return arg; + } +} diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 1995670c06a3..a0e1603f75ef 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2997,11 +2997,11 @@ <!-- [CHAR LIMIT=NONE] Stub notification title for an app running a service that has provided a bad bad notification for itself. --> <string name="app_running_notification_title"><xliff:g id="app_name">%1$s</xliff:g> - running</string> + is running</string> <!-- [CHAR LIMIT=NONE] Stub notification text for an app running a service that has provided a bad bad notification for itself. --> - <string name="app_running_notification_text"><xliff:g id="app_name">%1$s</xliff:g> - is currently running</string> + <string name="app_running_notification_text">Touch for more information + or to stop the app.</string> <!-- Preference framework strings. --> <string name="ok">OK</string> diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b80a166aa61e..917a47df52be 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -50,6 +50,7 @@ public class AudioManager { private long mVolumeKeyUpTime; private final boolean mUseMasterVolume; private final boolean mUseVolumeKeySounds; + private final Binder mToken = new Binder(); private static String TAG = "AudioManager"; /** @@ -2075,7 +2076,8 @@ public class AudioManager { IAudioService service = getService(); try { // pi != null - service.registerMediaButtonIntent(pi, eventReceiver); + service.registerMediaButtonIntent(pi, eventReceiver, + eventReceiver == null ? mToken : null); } catch (RemoteException e) { Log.e(TAG, "Dead object in registerMediaButtonIntent"+e); } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b22aa1d5df8b..773d7b61cd7a 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -530,6 +530,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // Register for package removal intent broadcasts for media button receiver persistence IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); + pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); pkgFilter.addDataScheme("package"); context.registerReceiver(mReceiver, pkgFilter); @@ -4033,14 +4036,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished { 0, null, SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); - } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { + } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) + || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) { if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { // a package is being removed, not replaced String packageName = intent.getData().getSchemeSpecificPart(); if (packageName != null) { - removeMediaButtonReceiverForPackage(packageName); + cleanupMediaButtonReceiverForPackage(packageName, true); } } + } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) + || action.equals(Intent.ACTION_PACKAGE_CHANGED)) { + String packageName = intent.getData().getSchemeSpecificPart(); + if (packageName != null) { + cleanupMediaButtonReceiverForPackage(packageName, false); + } } else if (action.equals(Intent.ACTION_SCREEN_ON)) { AudioSystem.setParameters("screen_state=on"); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { @@ -4847,8 +4857,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } - private static class RemoteControlStackEntry { + private static class RemoteControlStackEntry implements DeathRecipient { public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + final public AudioService mService; /** * The target for the ACTION_MEDIA_BUTTON events. * Always non null. @@ -4859,6 +4870,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { * Always non null. */ final public ComponentName mReceiverComponent; + public IBinder mToken; public String mCallingPackageName; public int mCallingUid; /** @@ -4889,9 +4901,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } /** precondition: mediaIntent != null */ - public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { + public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent, + ComponentName eventReceiver, IBinder token) { + mService = service; mMediaIntent = mediaIntent; mReceiverComponent = eventReceiver; + mToken = token; mCallingUid = -1; mRcClient = null; mRccId = ++sLastRccId; @@ -4901,6 +4916,17 @@ public class AudioService extends IAudioService.Stub implements OnFinished { RemoteControlClient.PLAYBACK_SPEED_1X); resetPlaybackInfo(); + if (mToken != null) { + try { + mToken.linkToDeath(this, 0); + } catch (RemoteException e) { + mService.mAudioHandler.post(new Runnable() { + @Override public void run() { + mService.unregisterMediaButtonIntent(mMediaIntent); + } + }); + } + } } public void unlinkToRcClientDeath() { @@ -4916,9 +4942,22 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } + public void destroy() { + unlinkToRcClientDeath(); + if (mToken != null) { + mToken.unlinkToDeath(this, 0); + mToken = null; + } + } + + @Override + public void binderDied() { + mService.unregisterMediaButtonIntent(mMediaIntent); + } + @Override protected void finalize() throws Throwable { - unlinkToRcClientDeath();// unlink exception handled inside method + destroy(); // unlink exception handled inside method super.finalize(); } } @@ -5017,11 +5056,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished { * Remove any entry in the remote control stack that has the same package name as packageName * Pre-condition: packageName != null */ - private void removeMediaButtonReceiverForPackage(String packageName) { + private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) { synchronized(mRCStack) { if (mRCStack.empty()) { return; } else { + final PackageManager pm = mContext.getPackageManager(); RemoteControlStackEntry oldTop = mRCStack.peek(); Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); // iterate over the stack entries @@ -5029,10 +5069,19 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // evaluated it, traversal order doesn't matter here) while(stackIterator.hasNext()) { RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); - if (packageName.equals(rcse.mMediaIntent.getCreatorPackage())) { + if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) { // a stack entry is from the package being removed, remove it from the stack stackIterator.remove(); - rcse.unlinkToRcClientDeath(); + rcse.destroy(); + } else if (rcse.mReceiverComponent != null) { + try { + // Check to see if this receiver still exists. + pm.getReceiverInfo(rcse.mReceiverComponent, 0); + } catch (PackageManager.NameNotFoundException e) { + // Not found -- remove it! + stackIterator.remove(); + rcse.destroy(); + } } } if (mRCStack.empty()) { @@ -5075,7 +5124,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mediaButtonIntent.setComponent(eventReceiver); PendingIntent pi = PendingIntent.getBroadcast(mContext, 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); - registerMediaButtonIntent(pi, eventReceiver); + registerMediaButtonIntent(pi, eventReceiver, null); } } @@ -5085,7 +5134,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished { * Called synchronized on mAudioFocusLock, then mRCStack * precondition: mediaIntent != null */ - private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target) { + private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target, + IBinder token) { // already at top of stack? if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { return; @@ -5107,7 +5157,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e); } if (!wasInsideStack) { - rcse = new RemoteControlStackEntry(mediaIntent, target); + rcse = new RemoteControlStackEntry(this, mediaIntent, target, token); } mRCStack.push(rcse); // rcse is never null @@ -5129,7 +5179,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { for (int index = mRCStack.size()-1; index >= 0; index--) { final RemoteControlStackEntry rcse = mRCStack.elementAt(index); if (rcse.mMediaIntent.equals(pi)) { - rcse.unlinkToRcClientDeath(); + rcse.destroy(); // ok to remove element while traversing the stack since we're leaving the loop mRCStack.removeElementAt(index); break; @@ -5417,12 +5467,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished { * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) * precondition: mediaIntent != null */ - public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { + public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver, + IBinder token) { Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); synchronized(mAudioFocusLock) { synchronized(mRCStack) { - pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver); + pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token); // new RC client, assume every type of information shall be queried checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 25aae8fc9e1e..13f6c021cc85 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -120,7 +120,7 @@ interface IAudioService { oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent); void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent); - void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c); + void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c, IBinder token); oneway void unregisterMediaButtonIntent(in PendingIntent pi); oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c); diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index 1f5ca354635f..c0fbd2eafb52 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -257,8 +257,10 @@ final public class MediaMuxer { } /** - * Writes an encoded sample into the muxer. The application needs to make - * sure that the samples are written into the right tracks. + * Writes an encoded sample into the muxer. + * <p>The application needs to make sure that the samples are written into + * the right tracks. Also, it needs to make sure the samples for each track + * are written in chronological order.</p> * @param byteBuf The encoded sample. * @param trackIndex The track index for this sample. * @param bufferInfo The buffer information related to this sample. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 52f552b84c00..c2dc15957ff0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -708,6 +708,7 @@ public class PhoneStatusBar extends BaseStatusBar { private View.OnClickListener mRecentsClickListener = new View.OnClickListener() { public void onClick(View v) { + awakenDreams(); toggleRecentApps(); } }; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 49460de385d2..5f9e92106f58 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -59,6 +59,8 @@ import android.os.UEventObserver; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; +import android.service.dreams.DreamService; +import android.service.dreams.IDreamManager; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -1801,7 +1803,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter : com.android.internal.R.anim.lock_screen_behind_enter); } - + + private static void awakenDreams() { + IDreamManager dreamManager = getDreamManager(); + if (dreamManager != null) { + try { + dreamManager.awaken(); + } catch (RemoteException e) { + // fine, stay asleep then + } + } + } + + static IDreamManager getDreamManager() { + return IDreamManager.Stub.asInterface( + ServiceManager.checkService(DreamService.DREAM_SERVICE)); + } + static ITelephony getTelephonyService() { return ITelephony.Stub.asInterface( ServiceManager.checkService(Context.TELEPHONY_SERVICE)); @@ -4550,6 +4568,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } void startDockOrHome() { + awakenDreams(); // We don't have dock home anymore. Home is home. If you lived here, you'd be home by now. mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT); } diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 8ff1c7d5fba7..fccaab56a9e1 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -376,37 +376,37 @@ class ServiceRecord extends Binder { // icon, but this used to be able to slip through, so for // those dirty apps give it the app's icon. foregroundNoti.icon = appInfo.icon; - if (foregroundNoti.contentView == null) { - // In this case the app may not have specified a - // content view... so we'll give them something to show. - CharSequence appName = appInfo.loadLabel( - ams.mContext.getPackageManager()); - if (appName == null) { - appName = appInfo.packageName; - } - Context ctx = null; - try { - ctx = ams.mContext.createPackageContext( - appInfo.packageName, 0); - Intent runningIntent = new Intent( - Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - runningIntent.setData(Uri.fromParts("package", - appInfo.packageName, null)); - PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0, - runningIntent, PendingIntent.FLAG_UPDATE_CURRENT); - foregroundNoti.setLatestEventInfo(ctx, - ams.mContext.getString( - com.android.internal.R.string - .app_running_notification_title, - appName), - ams.mContext.getString( - com.android.internal.R.string - .app_running_notification_text, - appName), - pi); - } catch (PackageManager.NameNotFoundException e) { - foregroundNoti.icon = 0; - } + + // Do not allow apps to present a sneaky invisible content view either. + foregroundNoti.contentView = null; + foregroundNoti.bigContentView = null; + CharSequence appName = appInfo.loadLabel( + ams.mContext.getPackageManager()); + if (appName == null) { + appName = appInfo.packageName; + } + Context ctx = null; + try { + ctx = ams.mContext.createPackageContext( + appInfo.packageName, 0); + Intent runningIntent = new Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + runningIntent.setData(Uri.fromParts("package", + appInfo.packageName, null)); + PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0, + runningIntent, PendingIntent.FLAG_UPDATE_CURRENT); + foregroundNoti.setLatestEventInfo(ctx, + ams.mContext.getString( + com.android.internal.R.string + .app_running_notification_title, + appName), + ams.mContext.getString( + com.android.internal.R.string + .app_running_notification_text, + appName), + pi); + } catch (PackageManager.NameNotFoundException e) { + foregroundNoti.icon = 0; } } if (foregroundNoti.icon == 0) { diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java index 5d0b155f7253..c7c8aa2e8031 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java @@ -49,6 +49,8 @@ public class NotificationBuilderTest extends Activity { private final static String TAG = "NotificationTestList"; + private final static String NOTIFY_TAG = "foo"; + NotificationManager mNM; Handler mHandler; int mStartDelay; @@ -196,7 +198,7 @@ public class NotificationBuilderTest extends Activity final Notification n = buildNotification(id); mHandler.postDelayed(new Runnable() { public void run() { - mNM.notify(id, n); + mNM.notify(NOTIFY_TAG, id, n); } }, mStartDelay); } |