Merge "Use free for memory chunks allocated through memalign."
diff --git a/Android.mk b/Android.mk
index c8576a0..b9cd7bf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,6 +69,7 @@
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
+ core/java/android/app/INotificationListener.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 50438e6..d661daa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1174,6 +1174,7 @@
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
+ field public static final int windowOverscan = 16843727; // 0x10103cf
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1693,6 +1694,7 @@
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
+ field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1711,9 +1713,11 @@
field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
+ field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
+ field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1736,9 +1740,11 @@
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
+ field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
+ field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1746,12 +1752,14 @@
field public static final int Theme_Light = 16973836; // 0x103000c
field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
+ field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_NoDisplay = 16973909; // 0x1030055
field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
+ field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
field public static final int Theme_Panel = 16973913; // 0x1030059
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -5840,6 +5848,8 @@
field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
+ field public static final java.lang.String ACTION_IDLE_MAINTENANCE_END = "android.intent.action.ACTION_IDLE_MAINTENANCE_END";
+ field public static final java.lang.String ACTION_IDLE_MAINTENANCE_START = "android.intent.action.ACTION_IDLE_MAINTENANCE_START";
field public static final java.lang.String ACTION_INPUT_METHOD_CHANGED = "android.intent.action.INPUT_METHOD_CHANGED";
field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
@@ -11441,6 +11451,11 @@
field public static final int MPEG4ProfileSimpleFBA = 128; // 0x80
field public static final int MPEG4ProfileSimpleFace = 64; // 0x40
field public static final int MPEG4ProfileSimpleScalable = 2; // 0x2
+ field public static final int VP8Level_Version0 = 1; // 0x1
+ field public static final int VP8Level_Version1 = 2; // 0x2
+ field public static final int VP8Level_Version2 = 4; // 0x4
+ field public static final int VP8Level_Version3 = 8; // 0x8
+ field public static final int VP8ProfileMain = 1; // 0x1
field public int level;
field public int profile;
}
@@ -22961,9 +22976,14 @@
public class EasyEditSpan implements android.text.ParcelableSpan {
ctor public EasyEditSpan();
+ ctor public EasyEditSpan(android.app.PendingIntent);
+ ctor public EasyEditSpan(android.os.Parcel);
method public int describeContents();
method public int getSpanTypeId();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String EXTRA_TEXT_CHANGED_TYPE = "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
+ field public static final int TEXT_DELETED = 1; // 0x1
+ field public static final int TEXT_MODIFIED = 2; // 0x2
}
public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
@@ -26245,6 +26265,7 @@
field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000
field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80
field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000
+ field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000
field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100
field public static final int FLAG_LAYOUT_NO_LIMITS = 512; // 0x200
field public static final int FLAG_NOT_FOCUSABLE = 8; // 0x8
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk
index 8b321b3..f8350dc 100644
--- a/cmds/am/Android.mk
+++ b/cmds/am/Android.mk
@@ -1,31 +1,15 @@
# Copyright 2008 The Android Open Source Project
#
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
+include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := am
include $(BUILD_JAVA_LIBRARY)
include $(CLEAR_VARS)
-ALL_PREBUILT += $(TARGET_OUT)/bin/am
-$(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP)
- $(transform-prebuilt-to-target)
-
-NOTICE_FILE := NOTICE
-files_noticed := bin/am
-
-# Generate rules for a single file. The argument is the file path relative to
-# the installation root
-define make-notice-file
-
-$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
- @echo Notice file: $$< -- $$@
- @mkdir -p $$(dir $$@)
- @cat $$< >> $$@
-
-$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
-
-endef
-
-$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
+LOCAL_MODULE := am
+LOCAL_SRC_FILES := am
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3c1fbfe..9fa7dbb 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,7 +26,6 @@
import android.app.Instrumentation;
import android.app.UiAutomationConnection;
import android.content.ComponentName;
-import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.IPackageManager;
@@ -39,7 +38,6 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.AndroidException;
-import android.view.Display;
import android.view.IWindowManager;
import java.io.BufferedReader;
@@ -134,10 +132,6 @@
runMonitor();
} else if (op.equals("screen-compat")) {
runScreenCompat();
- } else if (op.equals("display-size")) {
- runDisplaySize();
- } else if (op.equals("display-density")) {
- runDisplayDensity();
} else if (op.equals("to-uri")) {
runToUri(false);
} else if (op.equals("to-intent-uri")) {
@@ -1201,82 +1195,6 @@
} while (packageName != null);
}
- private void runDisplaySize() throws Exception {
- String size = nextArgRequired();
- int w, h;
- if ("reset".equals(size)) {
- w = h = -1;
- } else {
- int div = size.indexOf('x');
- if (div <= 0 || div >= (size.length()-1)) {
- System.err.println("Error: bad size " + size);
- return;
- }
- String wstr = size.substring(0, div);
- String hstr = size.substring(div+1);
- try {
- w = Integer.parseInt(wstr);
- h = Integer.parseInt(hstr);
- } catch (NumberFormatException e) {
- System.err.println("Error: bad number " + e);
- return;
- }
- }
-
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
- Context.WINDOW_SERVICE));
- if (wm == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to window manager; is the system running?");
- }
-
- try {
- if (w >= 0 && h >= 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
- } else {
- wm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
- }
- } catch (RemoteException e) {
- }
- }
-
- private void runDisplayDensity() throws Exception {
- String densityStr = nextArgRequired();
- int density;
- if ("reset".equals(densityStr)) {
- density = -1;
- } else {
- try {
- density = Integer.parseInt(densityStr);
- } catch (NumberFormatException e) {
- System.err.println("Error: bad number " + e);
- return;
- }
- if (density < 72) {
- System.err.println("Error: density must be >= 72");
- return;
- }
- }
-
- IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
- Context.WINDOW_SERVICE));
- if (wm == null) {
- System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to window manager; is the system running?");
- }
-
- try {
- if (density > 0) {
- // TODO(multidisplay): For now Configuration only applies to main screen.
- wm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
- } else {
- wm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
- }
- } catch (RemoteException e) {
- }
- }
-
private void runToUri(boolean intentScheme) throws Exception {
Intent intent = makeIntent(UserHandle.USER_CURRENT);
System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0));
@@ -1454,8 +1372,6 @@
" am clear-debug-app\n" +
" am monitor [--gdb <port>]\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
- " am display-size [reset|WxH]\n" +
- " am display-density [reset|DENSITY]\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
" am switch-user <USER_ID>\n" +
@@ -1524,17 +1440,13 @@
"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." +
+ " 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 display-size: override display size.\n" +
- "\n" +
- "am display-density: override display density.\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" +
diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk
index 88c46f2..9302e2f 100644
--- a/cmds/content/Android.mk
+++ b/cmds/content/Android.mk
@@ -1,33 +1,15 @@
# Copyright 2012 The Android Open Source Project
LOCAL_PATH:= $(call my-dir)
+
include $(CLEAR_VARS)
-
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_MODULE := content
-
include $(BUILD_JAVA_LIBRARY)
include $(CLEAR_VARS)
-ALL_PREBUILT += $(TARGET_OUT)/bin/content
-$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP)
- $(transform-prebuilt-to-target)
-
-NOTICE_FILE := NOTICE
-files_noticed := bin/content
-
-# Generate rules for a single file. The argument is the file path relative to
-# the installation root
-define make-notice-file
-
-$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
- @echo Notice file: $$< -- $$@
- @mkdir -p $$(dir $$@)
- @cat $$< >> $$@
-
-$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
-
-endef
-
-$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
+LOCAL_MODULE := content
+LOCAL_SRC_FILES := content
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk
new file mode 100644
index 0000000..3f3795f
--- /dev/null
+++ b/cmds/wm/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 := wm
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := wm
+LOCAL_SRC_FILES := wm
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/wm/MODULE_LICENSE_APACHE2 b/cmds/wm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/wm/MODULE_LICENSE_APACHE2
diff --git a/cmds/wm/NOTICE b/cmds/wm/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/wm/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/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
new file mode 100644
index 0000000..f48764f
--- /dev/null
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -0,0 +1,241 @@
+/*
+**
+** 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.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.AndroidException;
+import android.view.Display;
+import android.view.IWindowManager;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Wm {
+
+ 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.
+ *
+ * @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);
+ }
+ }
+
+ private void run(String[] args) throws Exception {
+ if (args.length < 1) {
+ showUsage();
+ return;
+ }
+
+ mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
+ Context.WINDOW_SERVICE));
+ if (mWm == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to window manager; is the system running?");
+ }
+
+ mArgs = args;
+ String op = args[0];
+ mNextArg = 1;
+
+ if (op.equals("size")) {
+ runDisplaySize();
+ } else if (op.equals("density")) {
+ runDisplayDensity();
+ } else if (op.equals("overscan")) {
+ runDisplayOverscan();
+ } else {
+ throw new IllegalArgumentException("Unknown command: " + op);
+ }
+ }
+
+ private void runDisplaySize() throws Exception {
+ String size = nextArgRequired();
+ int w, h;
+ if ("reset".equals(size)) {
+ w = h = -1;
+ } else {
+ int div = size.indexOf('x');
+ if (div <= 0 || div >= (size.length()-1)) {
+ System.err.println("Error: bad size " + size);
+ return;
+ }
+ String wstr = size.substring(0, div);
+ String hstr = size.substring(div+1);
+ try {
+ w = Integer.parseInt(wstr);
+ h = Integer.parseInt(hstr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: bad number " + e);
+ return;
+ }
+ }
+
+ try {
+ if (w >= 0 && h >= 0) {
+ // TODO(multidisplay): For now Configuration only applies to main screen.
+ mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
+ } else {
+ mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void runDisplayDensity() throws Exception {
+ String densityStr = nextArgRequired();
+ int density;
+ if ("reset".equals(densityStr)) {
+ density = -1;
+ } else {
+ try {
+ density = Integer.parseInt(densityStr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: bad number " + e);
+ return;
+ }
+ if (density < 72) {
+ System.err.println("Error: density must be >= 72");
+ return;
+ }
+ }
+
+ try {
+ if (density > 0) {
+ // TODO(multidisplay): For now Configuration only applies to main screen.
+ mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
+ } else {
+ mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void runDisplayOverscan() throws Exception {
+ String overscanStr = nextArgRequired();
+ Rect rect = new Rect();
+ int density;
+ if ("reset".equals(overscanStr)) {
+ rect.set(0, 0, 0, 0);
+ } else {
+ final Pattern FLATTENED_PATTERN = Pattern.compile(
+ "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)");
+ Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr);
+ if (!matcher.matches()) {
+ System.err.println("Error: bad rectangle arg: " + overscanStr);
+ return;
+ }
+ rect.left = Integer.parseInt(matcher.group(1));
+ rect.top = Integer.parseInt(matcher.group(2));
+ rect.right = Integer.parseInt(matcher.group(3));
+ rect.bottom = Integer.parseInt(matcher.group(4));
+ }
+
+ try {
+ mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom);
+ } 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: override display size.\n" +
+ "\n" +
+ "wm density: override display density.\n" +
+ "\n" +
+ "wm overscan: set overscan area for display.\n"
+ );
+ }
+}
diff --git a/cmds/wm/wm b/cmds/wm/wm
new file mode 100755
index 0000000..f7a5bc7
--- /dev/null
+++ b/cmds/wm/wm
@@ -0,0 +1,6 @@
+# Script to start "wm" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/wm.jar
+exec app_process $base/bin com.android.commands.wm.Wm "$@"
diff --git a/core/java/android/app/INotificationListener.aidl b/core/java/android/app/INotificationListener.aidl
new file mode 100644
index 0000000..f010a2a
--- /dev/null
+++ b/core/java/android/app/INotificationListener.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 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 android.app;
+
+import com.android.internal.statusbar.StatusBarNotification;
+
+/** @hide */
+oneway interface INotificationListener
+{
+ void onNotificationPosted(in StatusBarNotification notification);
+ void onNotificationRemoved(in StatusBarNotification notification);
+}
\ No newline at end of file
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 1f4c81d..14bcc0d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -17,6 +17,7 @@
package android.app;
+import android.app.INotificationListener;
import android.app.ITransientNotification;
import android.app.Notification;
import android.content.Intent;
@@ -39,5 +40,8 @@
StatusBarNotification[] getActiveNotifications(String callingPkg);
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
+
+ void registerListener(in INotificationListener listener, int userid);
+ void unregisterListener(in INotificationListener listener, int userid);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 434946c..bbf3b69 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2319,6 +2319,61 @@
"android.intent.action.DOCK_EVENT";
/**
+ * Broadcast Action: A broadcast when idle maintenance can be started.
+ * This means that the user is not interacting with the device and is
+ * not expected to do so soon. Typical use of the idle maintenance is
+ * to perform somehow expensive tasks that can be postponed at a moment
+ * when they will not degrade user experience.
+ * <p>
+ * <p class="note">In order to keep the device responsive in case of an
+ * unexpected user interaction, implementations of a maintenance task
+ * should be interruptible. In such a scenario a broadcast with action
+ * {@link #ACTION_IDLE_MAINTENANCE_END} will be sent. In other words, you
+ * should not do the maintenance work in
+ * {@link BroadcastReceiver#onReceive(Context, Intent)}, rather start a
+ * maintenance service by {@link Context#startService(Intent)}. Also
+ * you should hold a wake lock while your maintenance service is running
+ * to prevent the device going to sleep.
+ * </p>
+ * <p>
+ * <p class="note">This is a protected intent that can only be sent by
+ * the system.
+ * </p>
+ *
+ * @see #ACTION_IDLE_MAINTENANCE_END
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_IDLE_MAINTENANCE_START =
+ "android.intent.action.ACTION_IDLE_MAINTENANCE_START";
+
+ /**
+ * Broadcast Action: A broadcast when idle maintenance should be stopped.
+ * This means that the user was not interacting with the device as a result
+ * of which a broadcast with action {@link #ACTION_IDLE_MAINTENANCE_START}
+ * was sent and now the user started interacting with the device. Typical
+ * use of the idle maintenance is to perform somehow expensive tasks that
+ * can be postponed at a moment when they will not degrade user experience.
+ * <p>
+ * <p class="note">In order to keep the device responsive in case of an
+ * unexpected user interaction, implementations of a maintenance task
+ * should be interruptible. Hence, on receiving a broadcast with this
+ * action, the maintenance task should be interrupted as soon as possible.
+ * In other words, you should not do the maintenance work in
+ * {@link BroadcastReceiver#onReceive(Context, Intent)}, rather stop the
+ * maintenance service that was started on receiving of
+ * {@link #ACTION_IDLE_MAINTENANCE_START}.Also you should release the wake
+ * lock you acquired when your maintenance service started.
+ * </p>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ *
+ * @see #ACTION_IDLE_MAINTENANCE_START
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_IDLE_MAINTENANCE_END =
+ "android.intent.action.ACTION_IDLE_MAINTENANCE_END";
+
+ /**
* Broadcast Action: a remote intent is to be broadcasted.
*
* A remote intent is used for remote RPC between devices. The remote intent
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 1508d10..2ab9bf8 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -757,7 +757,7 @@
break;
case EASY_EDIT_SPAN:
- readSpan(p, sp, new EasyEditSpan());
+ readSpan(p, sp, new EasyEditSpan(p));
break;
case LOCALE_SPAN:
diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java
index 2feb719..03b4f60 100644
--- a/core/java/android/text/style/EasyEditSpan.java
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.app.PendingIntent;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextUtils;
@@ -25,12 +26,62 @@
* Provides an easy way to edit a portion of text.
* <p>
* The {@link TextView} uses this span to allow the user to delete a chuck of text in one click.
- * the text. {@link TextView} removes this span as soon as the text is edited, or the cursor moves.
+ * <p>
+ * {@link TextView} removes the span when the user deletes the whole text or modifies it.
+ * <p>
+ * This span can be also used to receive notification when the user deletes or modifies the text;
*/
public class EasyEditSpan implements ParcelableSpan {
+ /**
+ * The extra key field in the pending intent that describes how the text changed.
+ *
+ * @see #TEXT_DELETED
+ * @see #TEXT_MODIFIED
+ * @see #getPendingIntent()
+ */
+ public static final String EXTRA_TEXT_CHANGED_TYPE =
+ "android.text.style.EXTRA_TEXT_CHANGED_TYPE";
+
+ /**
+ * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is deleted.
+ */
+ public static final int TEXT_DELETED = 1;
+
+ /**
+ * The value of {@link #EXTRA_TEXT_CHANGED_TYPE} when the text wrapped by this span is modified.
+ */
+ public static final int TEXT_MODIFIED = 2;
+
+ private final PendingIntent mPendingIntent;
+
+ private boolean mDeleteEnabled;
+
+ /**
+ * Creates the span. No intent is sent when the wrapped text is modified or
+ * deleted.
+ */
public EasyEditSpan() {
- // Empty
+ mPendingIntent = null;
+ mDeleteEnabled = true;
+ }
+
+ /**
+ * @param pendingIntent The intent will be sent when the wrapped text is deleted or modified.
+ * When the pending intent is sent, {@link #EXTRA_TEXT_CHANGED_TYPE} is
+ * added in the intent to describe how the text changed.
+ */
+ public EasyEditSpan(PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
+ mDeleteEnabled = true;
+ }
+
+ /**
+ * Constructor called from {@link TextUtils} to restore the span.
+ */
+ public EasyEditSpan(Parcel source) {
+ mPendingIntent = source.readParcelable(null);
+ mDeleteEnabled = (source.readByte() == 1);
}
@Override
@@ -40,11 +91,39 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- // Empty
+ dest.writeParcelable(mPendingIntent, 0);
+ dest.writeByte((byte) (mDeleteEnabled ? 1 : 0));
}
@Override
public int getSpanTypeId() {
return TextUtils.EASY_EDIT_SPAN;
}
+
+ /**
+ * @return True if the {@link TextView} should offer the ability to delete the text.
+ *
+ * @hide
+ */
+ public boolean isDeleteEnabled() {
+ return mDeleteEnabled;
+ }
+
+ /**
+ * Enables or disables the deletion of the text.
+ *
+ * @hide
+ */
+ public void setDeleteEnabled(boolean value) {
+ mDeleteEnabled = value;
+ }
+
+ /**
+ * @return the pending intent to send when the wrapped text is deleted or modified.
+ *
+ * @hide
+ */
+ public PendingIntent getPendingIntent() {
+ return mPendingIntent;
+ }
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 758abb5..e6a7950 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -437,6 +437,20 @@
}
/**
+ * @hide
+ * Return a rectangle defining the insets of the overscan region of the display.
+ * Each field of the rectangle is the number of pixels the overscan area extends
+ * into the display on that side.
+ */
+ public void getOverscanInsets(Rect outRect) {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,
+ mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);
+ }
+ }
+
+ /**
* Returns the rotation of the screen from its "natural" orientation.
* The returned value may be {@link Surface#ROTATION_0 Surface.ROTATION_0}
* (no rotation), {@link Surface#ROTATION_90 Surface.ROTATION_90},
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 305fd5c..9fcd9b1 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -109,6 +109,30 @@
public int logicalHeight;
/**
+ * @hide
+ * Number of overscan pixels on the left side of the display.
+ */
+ public int overscanLeft;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the top side of the display.
+ */
+ public int overscanTop;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the right side of the display.
+ */
+ public int overscanRight;
+
+ /**
+ * @hide
+ * Number of overscan pixels on the bottom side of the display.
+ */
+ public int overscanBottom;
+
+ /**
* The rotation of the display relative to its natural orientation.
* May be one of {@link android.view.Surface#ROTATION_0},
* {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
@@ -196,6 +220,10 @@
&& largestNominalAppHeight == other.largestNominalAppHeight
&& logicalWidth == other.logicalWidth
&& logicalHeight == other.logicalHeight
+ && overscanLeft == other.overscanLeft
+ && overscanTop == other.overscanTop
+ && overscanRight == other.overscanRight
+ && overscanBottom == other.overscanBottom
&& rotation == other.rotation
&& refreshRate == other.refreshRate
&& logicalDensityDpi == other.logicalDensityDpi
@@ -222,6 +250,10 @@
largestNominalAppHeight = other.largestNominalAppHeight;
logicalWidth = other.logicalWidth;
logicalHeight = other.logicalHeight;
+ overscanLeft = other.overscanLeft;
+ overscanTop = other.overscanTop;
+ overscanRight = other.overscanRight;
+ overscanBottom = other.overscanBottom;
rotation = other.rotation;
refreshRate = other.refreshRate;
logicalDensityDpi = other.logicalDensityDpi;
@@ -243,6 +275,10 @@
largestNominalAppHeight = source.readInt();
logicalWidth = source.readInt();
logicalHeight = source.readInt();
+ overscanLeft = source.readInt();
+ overscanTop = source.readInt();
+ overscanRight = source.readInt();
+ overscanBottom = source.readInt();
rotation = source.readInt();
refreshRate = source.readFloat();
logicalDensityDpi = source.readInt();
@@ -265,6 +301,10 @@
dest.writeInt(largestNominalAppHeight);
dest.writeInt(logicalWidth);
dest.writeInt(logicalHeight);
+ dest.writeInt(overscanLeft);
+ dest.writeInt(overscanTop);
+ dest.writeInt(overscanRight);
+ dest.writeInt(overscanBottom);
dest.writeInt(rotation);
dest.writeFloat(refreshRate);
dest.writeInt(logicalDensityDpi);
@@ -318,18 +358,55 @@
// For debugging purposes
@Override
public String toString() {
- return "DisplayInfo{\"" + name + "\", app " + appWidth + " x " + appHeight
- + ", real " + logicalWidth + " x " + logicalHeight
- + ", largest app " + largestNominalAppWidth + " x " + largestNominalAppHeight
- + ", smallest app " + smallestNominalAppWidth + " x " + smallestNominalAppHeight
- + ", " + refreshRate + " fps"
- + ", rotation " + rotation
- + ", density " + logicalDensityDpi
- + ", " + physicalXDpi + " x " + physicalYDpi + " dpi"
- + ", layerStack " + layerStack
- + ", type " + Display.typeToString(type)
- + ", address " + address
- + flagsToString(flags) + "}";
+ StringBuilder sb = new StringBuilder();
+ sb.append("DisplayInfo{\"");
+ sb.append(name);
+ sb.append("\", app ");
+ sb.append(appWidth);
+ sb.append(" x ");
+ sb.append(appHeight);
+ sb.append(", real ");
+ sb.append(logicalWidth);
+ sb.append(" x ");
+ sb.append(logicalHeight);
+ if (overscanLeft != 0 || overscanTop != 0 || overscanRight != 0 || overscanBottom != 0) {
+ sb.append(", overscan (");
+ sb.append(overscanLeft);
+ sb.append(",");
+ sb.append(overscanTop);
+ sb.append(",");
+ sb.append(overscanRight);
+ sb.append(",");
+ sb.append(overscanBottom);
+ sb.append(")");
+ }
+ sb.append(", largest app ");
+ sb.append(largestNominalAppWidth);
+ sb.append(" x ");
+ sb.append(largestNominalAppHeight);
+ sb.append(", smallest app ");
+ sb.append(smallestNominalAppWidth);
+ sb.append(" x ");
+ sb.append(smallestNominalAppHeight);
+ sb.append(", ");
+ sb.append(refreshRate);
+ sb.append(" fps, rotation");
+ sb.append(rotation);
+ sb.append(", density ");
+ sb.append(logicalDensityDpi);
+ sb.append(" (");
+ sb.append(physicalXDpi);
+ sb.append(" x ");
+ sb.append(physicalYDpi);
+ sb.append(") dpi, layerStack ");
+ sb.append(layerStack);
+ sb.append(", type ");
+ sb.append(Display.typeToString(type));
+ sb.append(", address ");
+ sb.append(address);
+ sb.append(flagsToString(flags));
+ sb.append("}");
+ return sb.toString();
}
private static String flagsToString(int flags) {
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index e996e67..3bad98e 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -19,13 +19,109 @@
import android.graphics.Matrix;
/**
- * A display lists records a series of graphics related operation and can replay
+ * <p>A display list records a series of graphics related operations and can replay
* them later. Display lists are usually built by recording operations on a
- * {@link android.graphics.Canvas}. Replaying the operations from a display list
- * avoids executing views drawing code on every frame, and is thus much more
- * efficient.
+ * {@link HardwareCanvas}. Replaying the operations from a display list avoids
+ * executing application code on every frame, and is thus much more efficient.</p>
*
- * @hide
+ * <p>Display lists are used internally for all views by default, and are not
+ * typically used directly. One reason to consider using a display is a custom
+ * {@link View} implementation that needs to issue a large number of drawing commands.
+ * When the view invalidates, all the drawing commands must be reissued, even if
+ * large portions of the drawing command stream stay the same frame to frame, which
+ * can become a performance bottleneck. To solve this issue, a custom View might split
+ * its content into several display lists. A display list is updated only when its
+ * content, and only its content, needs to be updated.</p>
+ *
+ * <p>A text editor might for instance store each paragraph into its own display list.
+ * Thus when the user inserts or removes characters, only the display list of the
+ * affected paragraph needs to be recorded again.</p>
+ *
+ * <h3>Hardware acceleration</h3>
+ * <p>Display lists can only be replayed using a {@link HardwareCanvas}. They are not
+ * supported in software. Always make sure that the {@link android.graphics.Canvas}
+ * you are using to render a display list is hardware accelerated using
+ * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p>
+ *
+ * <h3>Creating a display list</h3>
+ * <pre class="prettyprint">
+ * HardwareRenderer renderer = myView.getHardwareRenderer();
+ * if (renderer != null) {
+ * DisplayList displayList = renderer.createDisplayList();
+ * HardwareCanvas canvas = displayList.start(width, height);
+ * try {
+ * // Draw onto the canvas
+ * // For instance: canvas.drawBitmap(...);
+ * } finally {
+ * displayList.end();
+ * }
+ * }
+ * </pre>
+ *
+ * <h3>Rendering a display list on a View</h3>
+ * <pre class="prettyprint">
+ * protected void onDraw(Canvas canvas) {
+ * if (canvas.isHardwareAccelerated()) {
+ * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
+ * hardwareCanvas.drawDisplayList(mDisplayList);
+ * }
+ * }
+ * </pre>
+ *
+ * <h3>Releasing resources</h3>
+ * <p>This step is not mandatory but recommended if you want to release resources
+ * held by a display list as soon as possible.</p>
+ * <pre class="prettyprint">
+ * // Mark this display list invalid, it cannot be used for drawing anymore,
+ * // and release resources held by this display list
+ * displayList.clear();
+ * </pre>
+ *
+ * <h3>Properties</h3>
+ * <p>In addition, a display list offers several properties, such as
+ * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all
+ * the drawing commands recorded within. For instance, these properties can be used
+ * to move around a large number of images without re-issuing all the individual
+ * <code>drawBitmap()</code> calls.</p>
+ *
+ * <pre class="prettyprint">
+ * private void createDisplayList() {
+ * HardwareRenderer renderer = getHardwareRenderer();
+ * if (renderer != null) {
+ * mDisplayList = renderer.createDisplayList();
+ * HardwareCanvas canvas = mDisplayList.start(width, height);
+ * try {
+ * for (Bitmap b : mBitmaps) {
+ * canvas.drawBitmap(b, 0.0f, 0.0f, null);
+ * canvas.translate(0.0f, b.getHeight());
+ * }
+ * } finally {
+ * displayList.end();
+ * }
+ * }
+ * }
+ *
+ * protected void onDraw(Canvas canvas) {
+ * if (canvas.isHardwareAccelerated()) {
+ * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas;
+ * hardwareCanvas.drawDisplayList(mDisplayList);
+ * }
+ * }
+ *
+ * private void moveContentBy(int x) {
+ * // This will move all the bitmaps recorded inside the display list
+ * // by x pixels to the right and redraw this view. All the commands
+ * // recorded in createDisplayList() won't be re-issued, only onDraw()
+ * // will be invoked and will execute very quickly
+ * mDisplayList.offsetLeftAndRight(x);
+ * invalidate();
+ * }
+ * </pre>
+ *
+ * <h3>Threading</h3>
+ * <p>Display lists must be created on and manipulated from the UI thread only.</p>
+ *
+ * @hide
*/
public abstract class DisplayList {
private boolean mDirty;
@@ -36,6 +132,8 @@
* When this flag is set, draw operations lying outside of the bounds of the
* display list will be culled early. It is recommeneded to always set this
* flag.
+ *
+ * @hide
*/
public static final int FLAG_CLIP_CHILDREN = 0x1;
@@ -44,14 +142,18 @@
/**
* Indicates that the display list is done drawing.
*
- * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+ * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+ *
+ * @hide
*/
public static final int STATUS_DONE = 0x0;
/**
* Indicates that the display list needs another drawing pass.
*
- * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+ * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+ *
+ * @hide
*/
public static final int STATUS_DRAW = 0x1;
@@ -59,7 +161,9 @@
* Indicates that the display list needs to re-execute its GL functors.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
- * @see HardwareCanvas#callDrawGLFunction(int)
+ * @see HardwareCanvas#callDrawGLFunction(int)
+ *
+ * @hide
*/
public static final int STATUS_INVOKE = 0x2;
@@ -67,53 +171,79 @@
* Indicates that the display list performed GL drawing operations.
*
* @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)
+ *
+ * @hide
*/
public static final int STATUS_DREW = 0x4;
/**
* Starts recording the display list. All operations performed on the
* returned canvas are recorded and stored in this display list.
- *
+ *
+ * Calling this method will mark the display list invalid until
+ * {@link #end()} is called. Only valid display lists can be replayed.
+ *
+ * @param width The width of the display list's viewport
+ * @param height The height of the display list's viewport
+ *
* @return A canvas to record drawing operations.
+ *
+ * @see #end()
+ * @see #isValid()
*/
- public abstract HardwareCanvas start();
+ public abstract HardwareCanvas start(int width, int height);
/**
* Ends the recording for this display list. A display list cannot be
- * replayed if recording is not finished.
+ * replayed if recording is not finished. Calling this method marks
+ * the display list valid and {@link #isValid()} will return true.
+ *
+ * @see #start(int, int)
+ * @see #isValid()
*/
public abstract void end();
/**
- * Invalidates the display list, indicating that it should be repopulated
- * with new drawing commands prior to being used again. Calling this method
- * causes calls to {@link #isValid()} to return <code>false</code>.
- */
- public abstract void invalidate();
-
- /**
- * Clears additional resources held onto by this display list. You should
- * only invoke this method after {@link #invalidate()}.
+ * Clears resources held onto by this display list. After calling this method
+ * {@link #isValid()} will return false.
+ *
+ * @see #isValid()
*/
public abstract void clear();
/**
- * Sets the dirty flag. When a display list is dirty, both
- * {@link #invalidate()} and {@link #clear()} should be invoked whenever
- * possible.
- *
- * @param dirty True to mark the display list dirty, false otherwise
+ * Sets the dirty flag. When a display list is dirty, {@link #clear()} should
+ * be invoked whenever possible.
*
* @see #isDirty()
+ * @see #clear()
+ *
+ * @hide
*/
- public void setDirty(boolean dirty) {
- mDirty = dirty;
+ public void markDirty() {
+ mDirty = true;
+ }
+
+ /**
+ * Removes the dirty flag. This method can be used to cancel a cleanup
+ * previously scheduled by setting the dirty flag.
+ *
+ * @see #isDirty()
+ * @see #clear()
+ *
+ * @hide
+ */
+ protected void clearDirty() {
+ mDirty = false;
}
/**
* Indicates whether the display list is dirty.
*
- * @see #setDirty(boolean)
+ * @see #markDirty()
+ * @see #clear()
+ *
+ * @hide
*/
public boolean isDirty() {
return mDirty;
@@ -131,6 +261,8 @@
* Return the amount of memory used by this display list.
*
* @return The size of this display list in bytes
+ *
+ * @hide
*/
public abstract int getSize();
@@ -139,228 +271,412 @@
///////////////////////////////////////////////////////////////////////////
/**
- * Set the caching property on the DisplayList, which indicates whether the DisplayList
- * holds a layer. Layer DisplayLists should avoid creating an alpha layer, since alpha is
+ * Set the caching property on the display list, which indicates whether the display list
+ * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is
* handled in the drawLayer operation directly (and more efficiently).
*
- * @param caching true if the DisplayList represents a hardware layer, false otherwise.
+ * @param caching true if the display list represents a hardware layer, false otherwise.
+ *
+ * @hide
*/
public abstract void setCaching(boolean caching);
/**
- * Set whether the DisplayList should clip itself to its bounds. This property is controlled by
+ * Set whether the display list should clip itself to its bounds. This property is controlled by
* the view's parent.
*
- * @param clipChildren true if the DisplayList should clip to its bounds
+ * @param clipChildren true if the display list should clip to its bounds
*/
public abstract void setClipChildren(boolean clipChildren);
/**
- * Set the static matrix on the DisplayList. This matrix exists if a custom ViewGroup
- * overrides
- * {@link ViewGroup#getChildStaticTransformation(View, android.view.animation.Transformation)}
- * and also has {@link ViewGroup#setStaticTransformationsEnabled(boolean)} set to true.
- * This matrix will be concatenated with any other matrices in the DisplayList to position
- * the view appropriately.
+ * Set the static matrix on the display list. The specified matrix is combined with other
+ * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
*
- * @param matrix The matrix
+ * @param matrix A transform matrix to apply to this display list
+ *
+ * @see #getMatrix(android.graphics.Matrix)
+ * @see #getMatrix()
*/
- public abstract void setStaticMatrix(Matrix matrix);
+ public abstract void setMatrix(Matrix matrix);
/**
- * Set the Animation matrix on the DisplayList. This matrix exists if an Animation is
- * currently playing on a View, and is set on the DisplayList during at draw() time. When
+ * Returns the static matrix set on this display list.
+ *
+ * @return A new {@link Matrix} instance populated with this display list's static
+ * matrix
+ *
+ * @see #getMatrix(android.graphics.Matrix)
+ * @see #setMatrix(android.graphics.Matrix)
+ */
+ public Matrix getMatrix() {
+ return getMatrix(new Matrix());
+ }
+
+ /**
+ * Copies this display list's static matrix into the specified matrix.
+ *
+ * @param matrix The {@link Matrix} instance in which to copy this display
+ * list's static matrix. Cannot be null
+ *
+ * @return The <code>matrix</code> parameter, for convenience
+ *
+ * @see #getMatrix()
+ * @see #setMatrix(android.graphics.Matrix)
+ */
+ public abstract Matrix getMatrix(Matrix matrix);
+
+ /**
+ * Set the Animation matrix on the display list. This matrix exists if an Animation is
+ * currently playing on a View, and is set on the display list during at draw() time. When
* the Animation finishes, the matrix should be cleared by sending <code>null</code>
* for the matrix parameter.
*
* @param matrix The matrix, null indicates that the matrix should be cleared.
+ *
+ * @hide
*/
public abstract void setAnimationMatrix(Matrix matrix);
/**
- * Sets the alpha value for the DisplayList
+ * Sets the translucency level for the display list.
*
- * @param alpha The translucency of the DisplayList
+ * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
+ *
* @see View#setAlpha(float)
+ * @see #getAlpha()
*/
public abstract void setAlpha(float alpha);
/**
- * Sets whether the DisplayList renders content which overlaps. Non-overlapping rendering
- * can use a fast path for alpha that avoids rendering to an offscreen buffer.
+ * Returns the translucency level of this display list.
*
- * @param hasOverlappingRendering
+ * @return A value between 0.0f and 1.0f
+ *
+ * @see #setAlpha(float)
+ */
+ public abstract float getAlpha();
+
+ /**
+ * Sets whether the display list renders content which overlaps. Non-overlapping rendering
+ * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default
+ * display lists consider they do not have overlapping content.
+ *
+ * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping,
+ * true otherwise.
+ *
* @see android.view.View#hasOverlappingRendering()
+ * @see #hasOverlappingRendering()
*/
public abstract void setHasOverlappingRendering(boolean hasOverlappingRendering);
/**
- * Sets the translationX value for the DisplayList
+ * Indicates whether the content of this display list overlaps.
*
- * @param translationX The translationX value of the DisplayList
+ * @return True if this display list renders content which overlaps, false otherwise.
+ *
+ * @see #setHasOverlappingRendering(boolean)
+ */
+ public abstract boolean hasOverlappingRendering();
+
+ /**
+ * Sets the translation value for the display list on the X axis
+ *
+ * @param translationX The X axis translation value of the display list, in pixels
+ *
* @see View#setTranslationX(float)
+ * @see #getTranslationX()
*/
public abstract void setTranslationX(float translationX);
/**
- * Sets the translationY value for the DisplayList
+ * Returns the translation value for this display list on the X axis, in pixels.
*
- * @param translationY The translationY value of the DisplayList
+ * @see #setTranslationX(float)
+ */
+ public abstract float getTranslationX();
+
+ /**
+ * Sets the translation value for the display list on the Y axis
+ *
+ * @param translationY The Y axis translation value of the display list, in pixels
+ *
* @see View#setTranslationY(float)
+ * @see #getTranslationY()
*/
public abstract void setTranslationY(float translationY);
/**
- * Sets the rotation value for the DisplayList
+ * Returns the translation value for this display list on the Y axis, in pixels.
*
- * @param rotation The rotation value of the DisplayList
+ * @see #setTranslationY(float)
+ */
+ public abstract float getTranslationY();
+
+ /**
+ * Sets the rotation value for the display list around the Z axis
+ *
+ * @param rotation The rotation value of the display list, in degrees
+ *
* @see View#setRotation(float)
+ * @see #getRotation()
*/
public abstract void setRotation(float rotation);
/**
- * Sets the rotationX value for the DisplayList
+ * Returns the rotation value for this display list around the Z axis, in degrees.
*
- * @param rotationX The rotationX value of the DisplayList
+ * @see #setRotation(float)
+ */
+ public abstract float getRotation();
+
+ /**
+ * Sets the rotation value for the display list around the X axis
+ *
+ * @param rotationX The rotation value of the display list, in degrees
+ *
* @see View#setRotationX(float)
+ * @see #getRotationX()
*/
public abstract void setRotationX(float rotationX);
/**
- * Sets the rotationY value for the DisplayList
+ * Returns the rotation value for this display list around the X axis, in degrees.
*
- * @param rotationY The rotationY value of the DisplayList
+ * @see #setRotationX(float)
+ */
+ public abstract float getRotationX();
+
+ /**
+ * Sets the rotation value for the display list around the Y axis
+ *
+ * @param rotationY The rotation value of the display list, in degrees
+ *
* @see View#setRotationY(float)
+ * @see #getRotationY()
*/
public abstract void setRotationY(float rotationY);
/**
- * Sets the scaleX value for the DisplayList
+ * Returns the rotation value for this display list around the Y axis, in degrees.
*
- * @param scaleX The scaleX value of the DisplayList
+ * @see #setRotationY(float)
+ */
+ public abstract float getRotationY();
+
+ /**
+ * Sets the scale value for the display list on the X axis
+ *
+ * @param scaleX The scale value of the display list
+ *
* @see View#setScaleX(float)
+ * @see #getScaleX()
*/
public abstract void setScaleX(float scaleX);
/**
- * Sets the scaleY value for the DisplayList
+ * Returns the scale value for this display list on the X axis.
*
- * @param scaleY The scaleY value of the DisplayList
+ * @see #setScaleX(float)
+ */
+ public abstract float getScaleX();
+
+ /**
+ * Sets the scale value for the display list on the Y axis
+ *
+ * @param scaleY The scale value of the display list
+ *
* @see View#setScaleY(float)
+ * @see #getScaleY()
*/
public abstract void setScaleY(float scaleY);
/**
- * Sets all of the transform-related values of the View onto the DisplayList
+ * Returns the scale value for this display list on the Y axis.
*
- * @param alpha The alpha value of the DisplayList
- * @param translationX The translationX value of the DisplayList
- * @param translationY The translationY value of the DisplayList
- * @param rotation The rotation value of the DisplayList
- * @param rotationX The rotationX value of the DisplayList
- * @param rotationY The rotationY value of the DisplayList
- * @param scaleX The scaleX value of the DisplayList
- * @param scaleY The scaleY value of the DisplayList
+ * @see #setScaleY(float)
+ */
+ public abstract float getScaleY();
+
+ /**
+ * Sets all of the transform-related values of the display list
+ *
+ * @param alpha The alpha value of the display list
+ * @param translationX The translationX value of the display list
+ * @param translationY The translationY value of the display list
+ * @param rotation The rotation value of the display list
+ * @param rotationX The rotationX value of the display list
+ * @param rotationY The rotationY value of the display list
+ * @param scaleX The scaleX value of the display list
+ * @param scaleY The scaleY value of the display list
+ *
+ * @hide
*/
public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
/**
- * Sets the pivotX value for the DisplayList
+ * Sets the pivot value for the display list on the X axis
*
- * @param pivotX The pivotX value of the DisplayList
+ * @param pivotX The pivot value of the display list on the X axis, in pixels
+ *
* @see View#setPivotX(float)
+ * @see #getPivotX()
*/
public abstract void setPivotX(float pivotX);
/**
- * Sets the pivotY value for the DisplayList
+ * Returns the pivot value for this display list on the X axis, in pixels.
*
- * @param pivotY The pivotY value of the DisplayList
+ * @see #setPivotX(float)
+ */
+ public abstract float getPivotX();
+
+ /**
+ * Sets the pivot value for the display list on the Y axis
+ *
+ * @param pivotY The pivot value of the display list on the Y axis, in pixels
+ *
* @see View#setPivotY(float)
+ * @see #getPivotY()
*/
public abstract void setPivotY(float pivotY);
/**
- * Sets the camera distance for the DisplayList
+ * Returns the pivot value for this display list on the Y axis, in pixels.
*
- * @param distance The distance in z of the camera of the DisplayList
+ * @see #setPivotY(float)
+ */
+ public abstract float getPivotY();
+
+ /**
+ * Sets the camera distance for the display list. Refer to
+ * {@link View#setCameraDistance(float)} for more information on how to
+ * use this property.
+ *
+ * @param distance The distance in Z of the camera of the display list
+ *
* @see View#setCameraDistance(float)
+ * @see #getCameraDistance()
*/
public abstract void setCameraDistance(float distance);
/**
- * Sets the left value for the DisplayList
+ * Returns the distance in Z of the camera of the display list.
*
- * @param left The left value of the DisplayList
+ * @see #setCameraDistance(float)
+ */
+ public abstract float getCameraDistance();
+
+ /**
+ * Sets the left position for the display list.
+ *
+ * @param left The left position, in pixels, of the display list
+ *
* @see View#setLeft(int)
+ * @see #getLeft()
*/
public abstract void setLeft(int left);
/**
- * Sets the top value for the DisplayList
+ * Returns the left position for the display list in pixels.
*
- * @param top The top value of the DisplayList
+ * @see #setLeft(int)
+ */
+ public abstract float getLeft();
+
+ /**
+ * Sets the top position for the display list.
+ *
+ * @param top The top position, in pixels, of the display list
+ *
* @see View#setTop(int)
+ * @see #getTop()
*/
public abstract void setTop(int top);
/**
- * Sets the right value for the DisplayList
+ * Returns the top position for the display list in pixels.
*
- * @param right The right value of the DisplayList
+ * @see #setTop(int)
+ */
+ public abstract float getTop();
+
+ /**
+ * Sets the right position for the display list.
+ *
+ * @param right The right position, in pixels, of the display list
+ *
* @see View#setRight(int)
+ * @see #getRight()
*/
public abstract void setRight(int right);
/**
- * Sets the bottom value for the DisplayList
+ * Returns the right position for the display list in pixels.
*
- * @param bottom The bottom value of the DisplayList
+ * @see #setRight(int)
+ */
+ public abstract float getRight();
+
+ /**
+ * Sets the bottom position for the display list.
+ *
+ * @param bottom The bottom position, in pixels, of the display list
+ *
* @see View#setBottom(int)
+ * @see #getBottom()
*/
public abstract void setBottom(int bottom);
/**
- * Sets the left and top values for the DisplayList
+ * Returns the bottom position for the display list in pixels.
*
- * @param left The left value of the DisplayList
- * @param top The top value of the DisplayList
- * @see View#setLeft(int)
- * @see View#setTop(int)
+ * @see #setBottom(int)
*/
- public abstract void setLeftTop(int left, int top);
+ public abstract float getBottom();
/**
- * Sets the left and top values for the DisplayList
+ * Sets the left and top positions for the display list
*
- * @param left The left value of the DisplayList
- * @param top The top value of the DisplayList
+ * @param left The left position of the display list, in pixels
+ * @param top The top position of the display list, in pixels
+ * @param right The right position of the display list, in pixels
+ * @param bottom The bottom position of the display list, in pixels
+ *
* @see View#setLeft(int)
* @see View#setTop(int)
+ * @see View#setRight(int)
+ * @see View#setBottom(int)
*/
public abstract void setLeftTopRightBottom(int left, int top, int right, int bottom);
/**
- * Offsets the left and right values for the DisplayList
+ * Offsets the left and right positions for the display list
*
- * @param offset The amount that the left and right values of the DisplayList are offset
+ * @param offset The amount that the left and right positions of the display
+ * list are offset, in pixels
+ *
* @see View#offsetLeftAndRight(int)
*/
- public abstract void offsetLeftRight(int offset);
+ public abstract void offsetLeftAndRight(float offset);
/**
- * Offsets the top and bottom values for the DisplayList
+ * Offsets the top and bottom values for the display list
*
- * @param offset The amount that the top and bottom values of the DisplayList are offset
+ * @param offset The amount that the top and bottom positions of the display
+ * list are offset, in pixels
+ *
* @see View#offsetTopAndBottom(int)
*/
- public abstract void offsetTopBottom(int offset);
+ public abstract void offsetTopAndBottom(float offset);
/**
- * Reset native resources. This is called when cleaning up the state of DisplayLists
+ * Reset native resources. This is called when cleaning up the state of display lists
* during destruction of hardware resources, to ensure that we do not hold onto
* obsolete resources after related resources are gone.
+ *
+ * @hide
*/
public abstract void reset();
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 40f2261..7ff8d09 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -377,24 +377,13 @@
}
private static native int nGetDisplayList(int renderer, int displayList);
-
- static void destroyDisplayList(int displayList) {
- nDestroyDisplayList(displayList);
+
+ @Override
+ void outputDisplayList(DisplayList displayList) {
+ nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
}
- private static native void nDestroyDisplayList(int displayList);
-
- static int getDisplayListSize(int displayList) {
- return nGetDisplayListSize(displayList);
- }
-
- private static native int nGetDisplayListSize(int displayList);
-
- static void setDisplayListName(int displayList, String name) {
- nSetDisplayListName(displayList, name);
- }
-
- private static native void nSetDisplayListName(int displayList, String name);
+ private static native void nOutputDisplayList(int renderer, int displayList);
@Override
public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) {
@@ -405,13 +394,6 @@
private static native int nDrawDisplayList(int renderer, int displayList,
Rect dirty, int flags);
- @Override
- void outputDisplayList(DisplayList displayList) {
- nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList());
- }
-
- private static native void nOutputDisplayList(int renderer, int displayList);
-
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////
@@ -955,6 +937,8 @@
@Override
public void drawLines(float[] pts, int offset, int count, Paint paint) {
+ if (count < 4) return;
+
if ((offset | count) < 0 || offset + count > pts.length) {
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
@@ -1078,6 +1062,8 @@
@Override
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
+ if (count < 2) return;
+
int modifiers = setupModifiers(paint, MODIFIER_COLOR_FILTER | MODIFIER_SHADER);
try {
nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index e9bd0c4..9c5cdb2 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -58,7 +58,7 @@
}
@Override
- public HardwareCanvas start() {
+ public HardwareCanvas start(int width, int height) {
if (mCanvas != null) {
throw new IllegalStateException("Recording has already started");
}
@@ -66,24 +66,25 @@
mValid = false;
mCanvas = GLES20RecordingCanvas.obtain(this);
mCanvas.start();
+
+ mCanvas.setViewport(width, height);
+ // The dirty rect should always be null for a display list
+ mCanvas.onPreDraw(null);
+
return mCanvas;
}
-
@Override
- public void invalidate() {
+ public void clear() {
+ clearDirty();
+
if (mCanvas != null) {
mCanvas.recycle();
mCanvas = null;
}
mValid = false;
- }
- @Override
- public void clear() {
- if (!mValid) {
- mBitmaps.clear();
- mChildDisplayLists.clear();
- }
+ mBitmaps.clear();
+ mChildDisplayLists.clear();
}
@Override
@@ -101,11 +102,12 @@
@Override
public void end() {
if (mCanvas != null) {
+ mCanvas.onPostDraw();
if (mFinalizer != null) {
mCanvas.end(mFinalizer.mNativeDisplayList);
} else {
mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
- GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
+ nSetDisplayListName(mFinalizer.mNativeDisplayList, mName);
}
mCanvas.recycle();
mCanvas = null;
@@ -116,9 +118,13 @@
@Override
public int getSize() {
if (mFinalizer == null) return 0;
- return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
+ return nGetDisplayListSize(mFinalizer.mNativeDisplayList);
}
+ private static native void nDestroyDisplayList(int displayList);
+ private static native int nGetDisplayListSize(int displayList);
+ private static native void nSetDisplayListName(int displayList, String name);
+
///////////////////////////////////////////////////////////////////////////
// Native View Properties
///////////////////////////////////////////////////////////////////////////
@@ -138,13 +144,21 @@
}
@Override
- public void setStaticMatrix(Matrix matrix) {
+ public void setMatrix(Matrix matrix) {
if (hasNativeDisplayList()) {
nSetStaticMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
}
}
@Override
+ public Matrix getMatrix(Matrix matrix) {
+ if (hasNativeDisplayList()) {
+ nGetMatrix(mFinalizer.mNativeDisplayList, matrix.native_instance);
+ }
+ return matrix;
+ }
+
+ @Override
public void setAnimationMatrix(Matrix matrix) {
if (hasNativeDisplayList()) {
nSetAnimationMatrix(mFinalizer.mNativeDisplayList,
@@ -160,6 +174,14 @@
}
@Override
+ public float getAlpha() {
+ if (hasNativeDisplayList()) {
+ return nGetAlpha(mFinalizer.mNativeDisplayList);
+ }
+ return 1.0f;
+ }
+
+ @Override
public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
if (hasNativeDisplayList()) {
nSetHasOverlappingRendering(mFinalizer.mNativeDisplayList, hasOverlappingRendering);
@@ -167,6 +189,15 @@
}
@Override
+ public boolean hasOverlappingRendering() {
+ //noinspection SimplifiableIfStatement
+ if (hasNativeDisplayList()) {
+ return nHasOverlappingRendering(mFinalizer.mNativeDisplayList);
+ }
+ return true;
+ }
+
+ @Override
public void setTranslationX(float translationX) {
if (hasNativeDisplayList()) {
nSetTranslationX(mFinalizer.mNativeDisplayList, translationX);
@@ -174,6 +205,14 @@
}
@Override
+ public float getTranslationX() {
+ if (hasNativeDisplayList()) {
+ return nGetTranslationX(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setTranslationY(float translationY) {
if (hasNativeDisplayList()) {
nSetTranslationY(mFinalizer.mNativeDisplayList, translationY);
@@ -181,6 +220,14 @@
}
@Override
+ public float getTranslationY() {
+ if (hasNativeDisplayList()) {
+ return nGetTranslationY(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRotation(float rotation) {
if (hasNativeDisplayList()) {
nSetRotation(mFinalizer.mNativeDisplayList, rotation);
@@ -188,6 +235,14 @@
}
@Override
+ public float getRotation() {
+ if (hasNativeDisplayList()) {
+ return nGetRotation(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRotationX(float rotationX) {
if (hasNativeDisplayList()) {
nSetRotationX(mFinalizer.mNativeDisplayList, rotationX);
@@ -195,6 +250,14 @@
}
@Override
+ public float getRotationX() {
+ if (hasNativeDisplayList()) {
+ return nGetRotationX(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRotationY(float rotationY) {
if (hasNativeDisplayList()) {
nSetRotationY(mFinalizer.mNativeDisplayList, rotationY);
@@ -202,6 +265,14 @@
}
@Override
+ public float getRotationY() {
+ if (hasNativeDisplayList()) {
+ return nGetRotationY(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setScaleX(float scaleX) {
if (hasNativeDisplayList()) {
nSetScaleX(mFinalizer.mNativeDisplayList, scaleX);
@@ -209,6 +280,14 @@
}
@Override
+ public float getScaleX() {
+ if (hasNativeDisplayList()) {
+ return nGetScaleX(mFinalizer.mNativeDisplayList);
+ }
+ return 1.0f;
+ }
+
+ @Override
public void setScaleY(float scaleY) {
if (hasNativeDisplayList()) {
nSetScaleY(mFinalizer.mNativeDisplayList, scaleY);
@@ -216,6 +295,14 @@
}
@Override
+ public float getScaleY() {
+ if (hasNativeDisplayList()) {
+ return nGetScaleY(mFinalizer.mNativeDisplayList);
+ }
+ return 1.0f;
+ }
+
+ @Override
public void setTransformationInfo(float alpha, float translationX, float translationY,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
if (hasNativeDisplayList()) {
@@ -232,6 +319,14 @@
}
@Override
+ public float getPivotX() {
+ if (hasNativeDisplayList()) {
+ return nGetPivotX(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setPivotY(float pivotY) {
if (hasNativeDisplayList()) {
nSetPivotY(mFinalizer.mNativeDisplayList, pivotY);
@@ -239,6 +334,14 @@
}
@Override
+ public float getPivotY() {
+ if (hasNativeDisplayList()) {
+ return nGetPivotY(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setCameraDistance(float distance) {
if (hasNativeDisplayList()) {
nSetCameraDistance(mFinalizer.mNativeDisplayList, distance);
@@ -246,6 +349,14 @@
}
@Override
+ public float getCameraDistance() {
+ if (hasNativeDisplayList()) {
+ return nGetCameraDistance(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setLeft(int left) {
if (hasNativeDisplayList()) {
nSetLeft(mFinalizer.mNativeDisplayList, left);
@@ -253,6 +364,14 @@
}
@Override
+ public float getLeft() {
+ if (hasNativeDisplayList()) {
+ return nGetLeft(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setTop(int top) {
if (hasNativeDisplayList()) {
nSetTop(mFinalizer.mNativeDisplayList, top);
@@ -260,6 +379,14 @@
}
@Override
+ public float getTop() {
+ if (hasNativeDisplayList()) {
+ return nGetTop(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRight(int right) {
if (hasNativeDisplayList()) {
nSetRight(mFinalizer.mNativeDisplayList, right);
@@ -267,6 +394,14 @@
}
@Override
+ public float getRight() {
+ if (hasNativeDisplayList()) {
+ return nGetRight(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setBottom(int bottom) {
if (hasNativeDisplayList()) {
nSetBottom(mFinalizer.mNativeDisplayList, bottom);
@@ -274,10 +409,11 @@
}
@Override
- public void setLeftTop(int left, int top) {
+ public float getBottom() {
if (hasNativeDisplayList()) {
- nSetLeftTop(mFinalizer.mNativeDisplayList, left, top);
+ return nGetBottom(mFinalizer.mNativeDisplayList);
}
+ return 0.0f;
}
@Override
@@ -288,25 +424,24 @@
}
@Override
- public void offsetLeftRight(int offset) {
+ public void offsetLeftAndRight(float offset) {
if (hasNativeDisplayList()) {
- nOffsetLeftRight(mFinalizer.mNativeDisplayList, offset);
+ nOffsetLeftAndRight(mFinalizer.mNativeDisplayList, offset);
}
}
@Override
- public void offsetTopBottom(int offset) {
+ public void offsetTopAndBottom(float offset) {
if (hasNativeDisplayList()) {
- nOffsetTopBottom(mFinalizer.mNativeDisplayList, offset);
+ nOffsetTopAndBottom(mFinalizer.mNativeDisplayList, offset);
}
}
private static native void nReset(int displayList);
- private static native void nOffsetTopBottom(int displayList, int offset);
- private static native void nOffsetLeftRight(int displayList, int offset);
+ private static native void nOffsetTopAndBottom(int displayList, float offset);
+ private static native void nOffsetLeftAndRight(int displayList, float offset);
private static native void nSetLeftTopRightBottom(int displayList, int left, int top,
int right, int bottom);
- private static native void nSetLeftTop(int displayList, int left, int top);
private static native void nSetBottom(int displayList, int bottom);
private static native void nSetRight(int displayList, int right);
private static native void nSetTop(int displayList, int top);
@@ -332,6 +467,23 @@
private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
+ private static native boolean nHasOverlappingRendering(int displayList);
+ private static native void nGetMatrix(int displayList, int matrix);
+ private static native float nGetAlpha(int displayList);
+ private static native float nGetLeft(int displayList);
+ private static native float nGetTop(int displayList);
+ private static native float nGetRight(int displayList);
+ private static native float nGetBottom(int displayList);
+ private static native float nGetCameraDistance(int displayList);
+ private static native float nGetScaleX(int displayList);
+ private static native float nGetScaleY(int displayList);
+ private static native float nGetTranslationX(int displayList);
+ private static native float nGetTranslationY(int displayList);
+ private static native float nGetRotation(int displayList);
+ private static native float nGetRotationX(int displayList);
+ private static native float nGetRotationY(int displayList);
+ private static native float nGetPivotX(int displayList);
+ private static native float nGetPivotY(int displayList);
///////////////////////////////////////////////////////////////////////////
// Finalization
@@ -347,7 +499,7 @@
@Override
protected void finalize() throws Throwable {
try {
- GLES20Canvas.destroyDisplayList(mNativeDisplayList);
+ nDestroyDisplayList(mNativeDisplayList);
} finally {
super.finalize();
}
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 812fb97..7ee628b 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -53,12 +53,12 @@
}
@Override
- boolean copyInto(Bitmap bitmap) {
+ public boolean copyInto(Bitmap bitmap) {
return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
}
@Override
- void destroy() {
+ public void destroy() {
if (mFinalizer != null) {
mFinalizer.destroy();
mFinalizer = null;
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index 44d4719..086e78c 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -92,6 +92,10 @@
if (currentCanvas instanceof GLES20Canvas) {
((GLES20Canvas) currentCanvas).resume();
}
+ HardwareCanvas canvas = getCanvas();
+ if (canvas != null) {
+ canvas.onPostDraw();
+ }
}
@Override
@@ -99,7 +103,10 @@
if (currentCanvas instanceof GLES20Canvas) {
((GLES20Canvas) currentCanvas).interrupt();
}
- return getCanvas();
+ HardwareCanvas canvas = getCanvas();
+ canvas.setViewport(mWidth, mHeight);
+ canvas.onPreDraw(null);
+ return canvas;
}
/**
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 3d19260..0dfed69 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -23,8 +23,8 @@
/**
* Hardware accelerated canvas.
- *
- * @hide
+ *
+ * @hide
*/
public abstract class HardwareCanvas extends Canvas {
private String mName;
@@ -46,6 +46,8 @@
* @param name The name of the canvas, can be null
*
* @see #getName()
+ *
+ * @hide
*/
public void setName(String name) {
mName = name;
@@ -57,6 +59,8 @@
* @return The name of the canvas or null
*
* @see #setName(String)
+ *
+ * @hide
*/
public String getName() {
return mName;
@@ -67,27 +71,43 @@
*
* @param dirty The dirty rectangle to update, can be null.
* @return {@link DisplayList#STATUS_DREW} if anything was drawn (such as a call to clear
- * the canvas).
+ * the canvas).
+ *
+ * @hide
*/
public abstract int onPreDraw(Rect dirty);
/**
* Invoked after all drawing operation have been performed.
+ *
+ * @hide
*/
public abstract void onPostDraw();
/**
+ * Draws the specified display list onto this canvas. The display list can only
+ * be drawn if {@link android.view.DisplayList#isValid()} returns true.
+ *
+ * @param displayList The display list to replay.
+ */
+ public void drawDisplayList(DisplayList displayList) {
+ drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
+ }
+
+ /**
* Draws the specified display list onto this canvas.
*
* @param displayList The display list to replay.
* @param dirty The dirty region to redraw in the next pass, matters only
- * if this method returns true, can be null.
+ * if this method returns {@link DisplayList#STATUS_DRAW}, can be null.
* @param flags Optional flags about drawing, see {@link DisplayList} for
* the possible flags.
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW}, or
* {@link DisplayList#STATUS_INVOKE}, or'd with {@link DisplayList#STATUS_DREW}
* if anything was drawn.
+ *
+ * @hide
*/
public abstract int drawDisplayList(DisplayList displayList, Rect dirty, int flags);
@@ -96,6 +116,8 @@
* tools to output display lists for selected nodes to the log.
*
* @param displayList The display list to be logged.
+ *
+ * @hide
*/
abstract void outputDisplayList(DisplayList displayList);
@@ -106,6 +128,8 @@
* @param x The left coordinate of the layer
* @param y The top coordinate of the layer
* @param paint The paint used to draw the layer
+ *
+ * @hide
*/
abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint);
@@ -118,6 +142,8 @@
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
* {@link DisplayList#STATUS_INVOKE}
+ *
+ * @hide
*/
public int callDrawGLFunction(int drawGLFunction) {
// Noop - this is done in the display list recorder subclass
@@ -131,6 +157,8 @@
*
* @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or
* {@link DisplayList#STATUS_INVOKE}
+ *
+ * @hide
*/
public int invokeFunctors(Rect dirty) {
return DisplayList.STATUS_DONE;
@@ -143,7 +171,9 @@
*
* @see #invokeFunctors(android.graphics.Rect)
* @see #callDrawGLFunction(int)
- * @see #detachFunctor(int)
+ * @see #detachFunctor(int)
+ *
+ * @hide
*/
abstract void detachFunctor(int functor);
@@ -154,7 +184,9 @@
*
* @see #invokeFunctors(android.graphics.Rect)
* @see #callDrawGLFunction(int)
- * @see #detachFunctor(int)
+ * @see #detachFunctor(int)
+ *
+ * @hide
*/
abstract void attachFunctor(int functor);
@@ -164,13 +196,17 @@
* @param layer The layer to update
*
* @see #clearLayerUpdates()
+ *
+ * @hide
*/
abstract void pushLayerUpdate(HardwareLayer layer);
/**
* Removes all enqueued layer updates.
*
- * @see #pushLayerUpdate(HardwareLayer)
+ * @see #pushLayerUpdate(HardwareLayer)
+ *
+ * @hide
*/
abstract void clearLayerUpdates();
}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index d3bc35a..18b838b 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -24,7 +24,7 @@
/**
* A hardware layer can be used to render graphics operations into a hardware
- * friendly buffer. For instance, with an OpenGL backend, a hardware layer
+ * friendly buffer. For instance, with an OpenGL backend a hardware layer
* would use a Frame Buffer Object (FBO.) The hardware layer can be used as
* a drawing cache when a complex set of graphics operations needs to be
* drawn several times.
@@ -68,7 +68,7 @@
* @param paint The paint used when the layer is drawn into the destination canvas.
* @see View#setLayerPaint(android.graphics.Paint)
*/
- void setLayerPaint(Paint paint) {}
+ void setLayerPaint(Paint paint) { }
/**
* Returns the minimum width of the layer.
@@ -144,6 +144,9 @@
* this layer.
*
* @return A hardware canvas, or null if a canvas cannot be created
+ *
+ * @see #start(android.graphics.Canvas)
+ * @see #end(android.graphics.Canvas)
*/
abstract HardwareCanvas getCanvas();
@@ -154,12 +157,14 @@
/**
* This must be invoked before drawing onto this layer.
+ *
* @param currentCanvas
*/
abstract HardwareCanvas start(Canvas currentCanvas);
-
+
/**
* This must be invoked after drawing onto this layer.
+ *
* @param currentCanvas
*/
abstract void end(Canvas currentCanvas);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 7c4bcfd..7929112 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -49,7 +49,7 @@
/**
* Interface for rendering a view hierarchy using hardware acceleration.
- *
+ *
* @hide
*/
public abstract class HardwareRenderer {
@@ -63,9 +63,9 @@
/**
* Turn on to only refresh the parts of the screen that need updating.
* When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
- * must also have the value "true".
+ * must also have the value "true".
*/
- public static final boolean RENDER_DIRTY_REGIONS = true;
+ static final boolean RENDER_DIRTY_REGIONS = true;
/**
* System property used to enable or disable dirty regions invalidation.
@@ -353,6 +353,8 @@
* resources.
*
* @param cacheDir A directory the current process can write to
+ *
+ * @hide
*/
public static void setupDiskCache(File cacheDir) {
nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
@@ -443,10 +445,11 @@
* Creates a new display list that can be used to record batches of
* drawing operations.
*
- * @param name The name of the display list, used for debugging purpose.
- * May be null
+ * @param name The name of the display list, used for debugging purpose. May be null.
*
* @return A new display list.
+ *
+ * @hide
*/
public abstract DisplayList createDisplayList(String name);
@@ -474,7 +477,6 @@
/**
* Creates a new {@link SurfaceTexture} that can be used to render into the
* specified hardware layer.
- *
*
* @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
*
@@ -1344,31 +1346,25 @@
dirty = beginFrame(canvas, dirty, surfaceState);
+ DisplayList displayList = buildDisplayList(view, canvas);
+
int saveCount = 0;
int status = DisplayList.STATUS_DONE;
try {
- view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
- == View.PFLAG_INVALIDATED;
- view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
- long buildDisplayListStartTime = startBuildDisplayListProfiling();
- canvas.clearLayerUpdates();
-
- DisplayList displayList = buildDisplayList(view);
status = prepareFrame(dirty);
saveCount = canvas.save();
callbacks.onHardwarePreDraw(canvas);
- endBuildDisplayListProfiling(buildDisplayListStartTime);
-
if (displayList != null) {
status = drawDisplayList(attachInfo, canvas, displayList, status);
} else {
// Shouldn't reach here
view.draw(canvas);
}
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "An error has occurred while drawing:", e);
} finally {
callbacks.onHardwarePostDraw(canvas);
canvas.restoreToCount(saveCount);
@@ -1396,6 +1392,23 @@
return false;
}
+ private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
+ view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
+ == View.PFLAG_INVALIDATED;
+ view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
+
+ long buildDisplayListStartTime = startBuildDisplayListProfiling();
+ canvas.clearLayerUpdates();
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ DisplayList displayList = view.getDisplayList();
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
+ endBuildDisplayListProfiling(buildDisplayListStartTime);
+
+ return displayList;
+ }
+
abstract void drawProfileData(View.AttachInfo attachInfo);
private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
@@ -1443,17 +1456,6 @@
}
}
- private static DisplayList buildDisplayList(View view) {
- DisplayList displayList;
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- try {
- displayList = view.getDisplayList();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- return displayList;
- }
-
private int prepareFrame(Rect dirty) {
int status;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
@@ -1971,12 +1973,12 @@
}
@Override
- HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+ public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
return new GLES20RenderLayer(width, height, isOpaque);
}
@Override
- SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
+ public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
return ((GLES20TextureLayer) layer).getSurfaceTexture();
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 885327c..e4ecb5c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,6 +65,8 @@
void setForcedDisplayDensity(int displayId, int density);
void clearForcedDisplayDensity(int displayId);
+ void setOverscan(int displayId, int left, int top, int right, int bottom);
+
// Is the device configured to have a full system bar for larger screens?
boolean hasSystemNavBar();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25cad87..dcf51e4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,6 @@
package android.view;
-import android.app.ActivityThread;
import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
@@ -10050,7 +10049,7 @@
mTop += offset;
mBottom += offset;
if (mDisplayList != null) {
- mDisplayList.offsetTopBottom(offset);
+ mDisplayList.offsetTopAndBottom(offset);
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -10098,7 +10097,7 @@
mLeft += offset;
mRight += offset;
if (mDisplayList != null) {
- mDisplayList.offsetLeftRight(offset);
+ mDisplayList.offsetLeftAndRight(offset);
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -11687,7 +11686,7 @@
}
if (mDisplayList != null) {
- mDisplayList.setDirty(false);
+ mDisplayList.clearDirty();
}
}
@@ -11966,7 +11965,7 @@
if (mAttachInfo != null) {
if (mDisplayList != null) {
- mDisplayList.setDirty(true);
+ mDisplayList.markDirty();
mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList);
}
mAttachInfo.mViewRootImpl.cancelInvalidate(this);
@@ -12670,8 +12669,9 @@
}
/**
- * @return The HardwareRenderer associated with that view or null if hardware rendering
- * is not supported or this this has not been attached to a window.
+ * @return The {@link HardwareRenderer} associated with that view or null if
+ * hardware rendering is not supported or this view is not attached
+ * to a window.
*
* @hide
*/
@@ -12726,15 +12726,13 @@
}
boolean caching = false;
- final HardwareCanvas canvas = displayList.start();
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
+ final HardwareCanvas canvas = displayList.start(width, height);
+
try {
- canvas.setViewport(width, height);
- // The dirty rect should always be null for a display list
- canvas.onPreDraw(null);
if (!isLayer && layerType != LAYER_TYPE_NONE) {
if (layerType == LAYER_TYPE_HARDWARE) {
final HardwareLayer layer = getHardwareLayer();
@@ -12772,8 +12770,6 @@
}
}
} finally {
- canvas.onPostDraw();
-
displayList.end();
displayList.setCaching(caching);
if (isLayer) {
@@ -12818,7 +12814,6 @@
private void clearDisplayList() {
if (mDisplayList != null) {
- mDisplayList.invalidate();
mDisplayList.clear();
}
}
@@ -13394,7 +13389,7 @@
alpha = transform.getAlpha();
}
if ((transformType & Transformation.TYPE_MATRIX) != 0) {
- displayList.setStaticMatrix(transform.getMatrix());
+ displayList.setMatrix(transform.getMatrix());
}
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a4898fc..5105fda 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4413,7 +4413,7 @@
v.mTop += offset;
v.mBottom += offset;
if (v.mDisplayList != null) {
- v.mDisplayList.offsetTopBottom(offset);
+ v.mDisplayList.offsetTopAndBottom(offset);
invalidateViewProperty(false, false);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1d86361..9b6dafb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1437,8 +1437,6 @@
}
// TODO: should handle create/resize failure
layerCanvas = mResizeBuffer.start(hwRendererCanvas);
- layerCanvas.setViewport(mWidth, mHeight);
- layerCanvas.onPreDraw(null);
final int restoreCount = layerCanvas.save();
int yoff;
@@ -1475,9 +1473,6 @@
} catch (OutOfMemoryError e) {
Log.w(TAG, "Not enough memory for content change anim buffer", e);
} finally {
- if (layerCanvas != null) {
- layerCanvas.onPostDraw();
- }
if (mResizeBuffer != null) {
mResizeBuffer.end(hwRendererCanvas);
if (!completed) {
@@ -2506,9 +2501,7 @@
for (int i = 0; i < count; i++) {
final DisplayList displayList = displayLists.get(i);
if (displayList.isDirty()) {
- displayList.invalidate();
displayList.clear();
- displayList.setDirty(false);
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6a67d8b..d236561 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -735,20 +735,20 @@
/**
* <p>Indicates whether this window should be hardware accelerated.
* Requesting hardware acceleration does not guarantee it will happen.</p>
- *
+ *
* <p>This flag can be controlled programmatically <em>only</em> to enable
* hardware acceleration. To enable hardware acceleration for a given
* window programmatically, do the following:</p>
- *
+ *
* <pre>
* Window w = activity.getWindow(); // in Activity's onCreate() for instance
* w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
* WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
* </pre>
- *
+ *
* <p>It is important to remember that this flag <strong>must</strong>
* be set before setting the content view of your activity or dialog.</p>
- *
+ *
* <p>This flag cannot be used to disable hardware acceleration after it
* was enabled in your manifest using
* {@link android.R.attr#hardwareAccelerated}. If you need to selectively
@@ -756,13 +756,19 @@
* for instance), make sure it is turned off in your manifest and enable it
* on your activity or dialog when you need it instead, using the method
* described above.</p>
- *
+ *
* <p>This flag is automatically set by the system if the
* {@link android.R.attr#hardwareAccelerated android:hardwareAccelerated}
* XML attribute is set to true on an activity or on the application.</p>
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
+ /** Window flag: allow window contents to extend in to the screen's
+ * overscan area, if there is one. The window should still correctly
+ * position its contents to take the overscan area into account.
+ */
+ public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
+
// ----- HIDDEN FLAGS.
// These start at the high bit and go down.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index b5d216a..192eded 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -458,6 +458,12 @@
public void setInitialDisplaySize(Display display, int width, int height, int density);
/**
+ * Called by window manager to set the overscan region that should be used for the
+ * given display.
+ */
+ public void setDisplayOverscan(Display display, int left, int top, int right, int bottom);
+
+ /**
* Check permissions when adding a window.
*
* @param attrs The window's LayoutParams.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c270e9d..dc305a5 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -20,6 +20,8 @@
import com.android.internal.widget.EditableInputConnection;
import android.R;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
import android.content.ClipData;
import android.content.ClipData.Item;
import android.content.Context;
@@ -1314,7 +1316,7 @@
blockDisplayList = mTextDisplayLists[blockIndex] =
mTextView.getHardwareRenderer().createDisplayList("Text " + blockIndex);
} else {
- if (blockIsInvalid) blockDisplayList.invalidate();
+ if (blockIsInvalid) blockDisplayList.clear();
}
final boolean blockDisplayListIsInvalid = !blockDisplayList.isValid();
@@ -1337,19 +1339,16 @@
// Rebuild display list if it is invalid
if (blockDisplayListIsInvalid) {
- final HardwareCanvas hardwareCanvas = blockDisplayList.start();
+ final HardwareCanvas hardwareCanvas = blockDisplayList.start(
+ right - left, bottom - top);
try {
- // Tighten the bounds of the viewport to the actual text size
- hardwareCanvas.setViewport(right - left, bottom - top);
- // The dirty rect should always be null for a display list
- hardwareCanvas.onPreDraw(null);
- // drawText is always relative to TextView's origin, this translation brings
- // this range of text back to the top left corner of the viewport
+ // drawText is always relative to TextView's origin, this translation
+ // brings this range of text back to the top left corner of the viewport
hardwareCanvas.translate(-left, -top);
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
- // No need to untranslate, previous context is popped after drawDisplayList
+ // No need to untranslate, previous context is popped after
+ // drawDisplayList
} finally {
- hardwareCanvas.onPostDraw();
blockDisplayList.end();
// Same as drawDisplayList below, handled by our TextView's parent
blockDisplayList.setClipChildren(false);
@@ -1430,7 +1429,7 @@
while (i < numberOfBlocks) {
final int blockIndex = blockIndices[i];
if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
- mTextDisplayLists[blockIndex].invalidate();
+ mTextDisplayLists[blockIndex].clear();
}
if (blockEndLines[i] >= lastLine) break;
i++;
@@ -1441,7 +1440,7 @@
void invalidateTextDisplayList() {
if (mTextDisplayLists != null) {
for (int i = 0; i < mTextDisplayLists.length; i++) {
- if (mTextDisplayLists[i] != null) mTextDisplayLists[i].invalidate();
+ if (mTextDisplayLists[i] != null) mTextDisplayLists[i].clear();
}
}
}
@@ -1893,10 +1892,23 @@
// Make sure there is only at most one EasyEditSpan in the text
if (mPopupWindow.mEasyEditSpan != null) {
- text.removeSpan(mPopupWindow.mEasyEditSpan);
+ mPopupWindow.mEasyEditSpan.setDeleteEnabled(false);
}
mPopupWindow.setEasyEditSpan((EasyEditSpan) span);
+ mPopupWindow.setOnDeleteListener(new EasyEditDeleteListener() {
+ @Override
+ public void onDeleteClick(EasyEditSpan span) {
+ Editable editable = (Editable) mTextView.getText();
+ int start = editable.getSpanStart(span);
+ int end = editable.getSpanEnd(span);
+ if (start >= 0 && end >= 0) {
+ sendNotification(EasyEditSpan.TEXT_DELETED, span);
+ mTextView.deleteText_internal(start, end);
+ }
+ editable.removeSpan(span);
+ }
+ });
if (mTextView.getWindowVisibility() != View.VISIBLE) {
// The window is not visible yet, ignore the text change.
@@ -1930,8 +1942,10 @@
@Override
public void onSpanChanged(Spannable text, Object span, int previousStart, int previousEnd,
int newStart, int newEnd) {
- if (mPopupWindow != null && span == mPopupWindow.mEasyEditSpan) {
- text.removeSpan(mPopupWindow.mEasyEditSpan);
+ if (mPopupWindow != null && span instanceof EasyEditSpan) {
+ EasyEditSpan easyEditSpan = (EasyEditSpan) span;
+ sendNotification(EasyEditSpan.TEXT_MODIFIED, easyEditSpan);
+ text.removeSpan(easyEditSpan);
}
}
@@ -1941,6 +1955,31 @@
mTextView.removeCallbacks(mHidePopup);
}
}
+
+ private void sendNotification(int textChangedType, EasyEditSpan span) {
+ try {
+ PendingIntent pendingIntent = span.getPendingIntent();
+ if (pendingIntent != null) {
+ Intent intent = new Intent();
+ intent.putExtra(EasyEditSpan.EXTRA_TEXT_CHANGED_TYPE, textChangedType);
+ pendingIntent.send(mTextView.getContext(), 0, intent);
+ }
+ } catch (CanceledException e) {
+ // This should not happen, as we should try to send the intent only once.
+ Log.w(TAG, "PendingIntent for notification cannot be sent", e);
+ }
+ }
+ }
+
+ /**
+ * Listens for the delete event triggered by {@link EasyEditPopupWindow}.
+ */
+ private interface EasyEditDeleteListener {
+
+ /**
+ * Clicks the delete pop-up.
+ */
+ void onDeleteClick(EasyEditSpan span);
}
/**
@@ -1953,6 +1992,7 @@
com.android.internal.R.layout.text_edit_action_popup_text;
private TextView mDeleteTextView;
private EasyEditSpan mEasyEditSpan;
+ private EasyEditDeleteListener mOnDeleteListener;
@Override
protected void createPopupWindow() {
@@ -1987,19 +2027,29 @@
mEasyEditSpan = easyEditSpan;
}
+ private void setOnDeleteListener(EasyEditDeleteListener listener) {
+ mOnDeleteListener = listener;
+ }
+
@Override
public void onClick(View view) {
- if (view == mDeleteTextView) {
- Editable editable = (Editable) mTextView.getText();
- int start = editable.getSpanStart(mEasyEditSpan);
- int end = editable.getSpanEnd(mEasyEditSpan);
- if (start >= 0 && end >= 0) {
- mTextView.deleteText_internal(start, end);
- }
+ if (view == mDeleteTextView
+ && mEasyEditSpan != null && mEasyEditSpan.isDeleteEnabled()
+ && mOnDeleteListener != null) {
+ mOnDeleteListener.onDeleteClick(mEasyEditSpan);
}
}
@Override
+ public void hide() {
+ if (mEasyEditSpan != null) {
+ mEasyEditSpan.setDeleteEnabled(false);
+ }
+ mOnDeleteListener = null;
+ super.hide();
+ }
+
+ @Override
protected int getTextOffset() {
// Place the pop-up at the end of the span
Editable editable = (Editable) mTextView.getText();
diff --git a/core/java/com/android/internal/statusbar/INotificationListener.java b/core/java/com/android/internal/statusbar/INotificationListener.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/INotificationListener.java
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 80573a7..a6bb7c7 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -41,6 +41,7 @@
#include <SkTemplates.h>
#include <SkXfermode.h>
+#include <DisplayList.h>
#include <DisplayListRenderer.h>
#include <LayerRenderer.h>
#include <OpenGLRenderer.h>
@@ -716,20 +717,6 @@
return renderer->getDisplayList(displayList);
}
-static jint android_view_GLES20Canvas_getDisplayListSize(JNIEnv* env,
- jobject clazz, DisplayList* displayList) {
- return displayList->getSize();
-}
-
-static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
- jobject clazz, DisplayList* displayList, jstring name) {
- if (name != NULL) {
- const char* textArray = env->GetStringUTFChars(name, NULL);
- displayList->setName(textArray);
- env->ReleaseStringUTFChars(name, textArray);
- }
-}
-
static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
jobject clazz) {
return new DisplayListRenderer;
@@ -740,11 +727,6 @@
renderer->reset();
}
-static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
- jobject clazz, DisplayList* displayList) {
- DisplayList::destroyDisplayListDeferred(displayList);
-}
-
static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
jobject dirty, jint flags) {
@@ -1044,17 +1026,13 @@
(void*) android_view_GLES20Canvas_getClipBounds },
{ "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList },
- { "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
- { "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
- { "nSetDisplayListName", "(ILjava/lang/String;)V",
- (void*) android_view_GLES20Canvas_setDisplayListName },
+ { "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nDrawDisplayList", "(IILandroid/graphics/Rect;I)I",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
{ "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
- { "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt },
{ "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume },
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index c5f52df..f7a5302 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -23,6 +23,7 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <DisplayList.h>
#include <DisplayListRenderer.h>
namespace android {
@@ -36,11 +37,34 @@
*/
#ifdef USE_OPENGL_RENDERER
+// ----------------------------------------------------------------------------
+// DisplayList view properties
+// ----------------------------------------------------------------------------
+
static void android_view_GLES20DisplayList_reset(JNIEnv* env,
jobject clazz, DisplayList* displayList) {
displayList->reset();
}
+static jint android_view_GLES20DisplayList_getDisplayListSize(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getSize();
+}
+
+static void android_view_GLES20DisplayList_setDisplayListName(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, jstring name) {
+ if (name != NULL) {
+ const char* textArray = env->GetStringUTFChars(name, NULL);
+ displayList->setName(textArray);
+ env->ReleaseStringUTFChars(name, textArray);
+ }
+}
+
+static void android_view_GLES20DisplayList_destroyDisplayList(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ DisplayList::destroyDisplayListDeferred(displayList);
+}
+
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -159,27 +183,112 @@
displayList->setBottom(bottom);
}
-static void android_view_GLES20DisplayList_setLeftTop(JNIEnv* env,
- jobject clazz, DisplayList* displayList, int left, int top) {
- displayList->setLeftTop(left, top);
-}
-
static void android_view_GLES20DisplayList_setLeftTopRightBottom(JNIEnv* env,
jobject clazz, DisplayList* displayList, int left, int top,
int right, int bottom) {
displayList->setLeftTopRightBottom(left, top, right, bottom);
}
-static void android_view_GLES20DisplayList_offsetLeftRight(JNIEnv* env,
- jobject clazz, DisplayList* displayList, int offset) {
+static void android_view_GLES20DisplayList_offsetLeftAndRight(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float offset) {
displayList->offsetLeftRight(offset);
}
-static void android_view_GLES20DisplayList_offsetTopBottom(JNIEnv* env,
- jobject clazz, DisplayList* displayList, int offset) {
+static void android_view_GLES20DisplayList_offsetTopAndBottom(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float offset) {
displayList->offsetTopBottom(offset);
}
+static void android_view_GLES20DisplayList_getMatrix(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, SkMatrix* matrix) {
+ SkMatrix* source = displayList->getStaticMatrix();
+ if (source) {
+ matrix->setConcat(SkMatrix::I(), *source);
+ } else {
+ matrix->setIdentity();
+ }
+}
+
+static jboolean android_view_GLES20DisplayList_hasOverlappingRendering(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->hasOverlappingRendering();
+}
+
+static jfloat android_view_GLES20DisplayList_getAlpha(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getAlpha();
+}
+
+static jfloat android_view_GLES20DisplayList_getLeft(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getLeft();
+}
+
+static jfloat android_view_GLES20DisplayList_getTop(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getTop();
+}
+
+static jfloat android_view_GLES20DisplayList_getRight(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getRight();
+}
+
+static jfloat android_view_GLES20DisplayList_getBottom(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getBottom();
+}
+
+static jfloat android_view_GLES20DisplayList_getCameraDistance(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getCameraDistance();
+}
+
+static jfloat android_view_GLES20DisplayList_getScaleX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getScaleX();
+}
+
+static jfloat android_view_GLES20DisplayList_getScaleY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getScaleY();
+}
+
+static jfloat android_view_GLES20DisplayList_getTranslationX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getTranslationX();
+}
+
+static jfloat android_view_GLES20DisplayList_getTranslationY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getTranslationY();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotation(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getRotation();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotationX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getRotationX();
+}
+
+static jfloat android_view_GLES20DisplayList_getRotationY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getRotationY();
+}
+
+static jfloat android_view_GLES20DisplayList_getPivotX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getPivotX();
+}
+
+static jfloat android_view_GLES20DisplayList_getPivotY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ return displayList->getPivotY();
+}
+
#endif // USE_OPENGL_RENDERER
// ----------------------------------------------------------------------------
@@ -190,6 +299,11 @@
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
+ { "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20DisplayList_destroyDisplayList },
+ { "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20DisplayList_getDisplayListSize },
+ { "nSetDisplayListName", "(ILjava/lang/String;)V",
+ (void*) android_view_GLES20DisplayList_setDisplayListName },
+
{ "nReset", "(I)V", (void*) android_view_GLES20DisplayList_reset },
{ "nSetCaching", "(IZ)V", (void*) android_view_GLES20DisplayList_setCaching },
{ "nSetStaticMatrix", "(II)V", (void*) android_view_GLES20DisplayList_setStaticMatrix },
@@ -214,12 +328,29 @@
{ "nSetTop", "(II)V", (void*) android_view_GLES20DisplayList_setTop },
{ "nSetRight", "(II)V", (void*) android_view_GLES20DisplayList_setRight },
{ "nSetBottom", "(II)V", (void*) android_view_GLES20DisplayList_setBottom },
- { "nSetLeftTop", "(III)V", (void*) android_view_GLES20DisplayList_setLeftTop },
{ "nSetLeftTopRightBottom","(IIIII)V",
(void*) android_view_GLES20DisplayList_setLeftTopRightBottom },
- { "nOffsetLeftRight", "(II)V", (void*) android_view_GLES20DisplayList_offsetLeftRight },
- { "nOffsetTopBottom", "(II)V", (void*) android_view_GLES20DisplayList_offsetTopBottom },
+ { "nOffsetLeftAndRight", "(IF)V", (void*) android_view_GLES20DisplayList_offsetLeftAndRight },
+ { "nOffsetTopAndBottom", "(IF)V", (void*) android_view_GLES20DisplayList_offsetTopAndBottom },
+
+ { "nGetMatrix", "(II)V", (void*) android_view_GLES20DisplayList_getMatrix },
+ { "nHasOverlappingRendering", "(I)Z", (void*) android_view_GLES20DisplayList_hasOverlappingRendering },
+ { "nGetAlpha", "(I)F", (void*) android_view_GLES20DisplayList_getAlpha },
+ { "nGetLeft", "(I)F", (void*) android_view_GLES20DisplayList_getLeft },
+ { "nGetTop", "(I)F", (void*) android_view_GLES20DisplayList_getTop },
+ { "nGetRight", "(I)F", (void*) android_view_GLES20DisplayList_getRight },
+ { "nGetBottom", "(I)F", (void*) android_view_GLES20DisplayList_getBottom },
+ { "nGetCameraDistance", "(I)F", (void*) android_view_GLES20DisplayList_getCameraDistance },
+ { "nGetScaleX", "(I)F", (void*) android_view_GLES20DisplayList_getScaleX },
+ { "nGetScaleY", "(I)F", (void*) android_view_GLES20DisplayList_getScaleY },
+ { "nGetTranslationX", "(I)F", (void*) android_view_GLES20DisplayList_getTranslationX },
+ { "nGetTranslationY", "(I)F", (void*) android_view_GLES20DisplayList_getTranslationY },
+ { "nGetRotation", "(I)F", (void*) android_view_GLES20DisplayList_getRotation },
+ { "nGetRotationX", "(I)F", (void*) android_view_GLES20DisplayList_getRotationX },
+ { "nGetRotationY", "(I)F", (void*) android_view_GLES20DisplayList_getRotationY },
+ { "nGetPivotX", "(I)F", (void*) android_view_GLES20DisplayList_getPivotX },
+ { "nGetPivotY", "(I)F", (void*) android_view_GLES20DisplayList_getPivotY },
#endif
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d77b504..8a53cc3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -170,6 +170,9 @@
<protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
<protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
+ <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
+ <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..57141d5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..8e28906
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..efdab73
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..307b86d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..2e28431
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..7a83451
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..9afc912
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..7d03855
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png
new file mode 100644
index 0000000..21f1e2c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png
new file mode 100644
index 0000000..600b861
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c11619c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png
new file mode 100644
index 0000000..91be10f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png
new file mode 100644
index 0000000..c921487
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png
new file mode 100644
index 0000000..4da6c6e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png
new file mode 100644
index 0000000..9c7d294
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png
new file mode 100644
index 0000000..c9f493a
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/spinner_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..02c799e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..286157c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..030f723
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..a5b10d2
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..10faec10
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..62a70ed
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..633b8d2
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..59ff556
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png
new file mode 100644
index 0000000..09d5aa4
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png
new file mode 100644
index 0000000..c320ea0
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png
new file mode 100644
index 0000000..a5f28fd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png
new file mode 100644
index 0000000..9e0d39c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png
new file mode 100644
index 0000000..24d928f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png
new file mode 100644
index 0000000..596ba2d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png
new file mode 100644
index 0000000..55b1af7
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png
new file mode 100644
index 0000000..bb0486a
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/spinner_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png
new file mode 100644
index 0000000..6f41b24
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png
new file mode 100644
index 0000000..5a96fc1
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png
new file mode 100644
index 0000000..96a6da5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png
new file mode 100644
index 0000000..849d795
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png
new file mode 100644
index 0000000..3d6d0f9
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png
new file mode 100644
index 0000000..1cbaf6c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png
new file mode 100644
index 0000000..878e90d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png
new file mode 100644
index 0000000..f25acc2
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_ab_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png
new file mode 100644
index 0000000..8d89c86
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png
new file mode 100644
index 0000000..6e3ca08
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png
new file mode 100644
index 0000000..2204091
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png
new file mode 100644
index 0000000..3e6684e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png
new file mode 100644
index 0000000..5129dee
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png
new file mode 100644
index 0000000..0f0289b
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png
new file mode 100644
index 0000000..795820b
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png
new file mode 100644
index 0000000..830edfd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/spinner_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 70797cb..7edb530 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -776,7 +776,7 @@
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Thử lại"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Đã vượt quá số lần Mở khóa bằng khuôn mặt tối đa"</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <string name="lockscreen_charged" msgid="321635745684060624">"Bị tính phí"</string>
+ <string name="lockscreen_charged" msgid="321635745684060624">"Pin đầy"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Kết nối bộ sạc của bạn."</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Không có thẻ SIM nào"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a3e5b2c..c73ff81 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -312,6 +312,8 @@
<attr name="windowNoTitle" format="boolean" />
<!-- Flag indicating whether this window should fill the entire screen. -->
<attr name="windowFullscreen" format="boolean" />
+ <!-- Flag indicating whether this window should extend into overscan region. -->
+ <attr name="windowOverscan" format="boolean" />
<!-- Flag indicating whether this is a floating window. -->
<attr name="windowIsFloating" format="boolean" />
<!-- Flag indicating whether this is a translucent window. -->
@@ -1562,6 +1564,7 @@
<attr name="windowFrame" />
<attr name="windowNoTitle" />
<attr name="windowFullscreen" />
+ <attr name="windowOverscan" />
<attr name="windowIsFloating" />
<attr name="windowIsTranslucent" />
<attr name="windowShowWallpaper" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0d80082..42e5cf1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2036,4 +2036,18 @@
<public type="attr" name="mipMap" id="0x010103cd" />
<public type="attr" name="mirrorForRtl" id="0x010103ce" />
+ <!-- ===============================================================
+ Resources added in version 19 of the platform
+ =============================================================== -->
+ <eat-comment />
+
+ <public type="attr" name="windowOverscan" />
+ <public type="style" name="Theme.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
+ <public type="style" name="Theme.Holo.NoActionBar.Overscan" />
+ <public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
+ <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
+ <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Overscan" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 75850dd..411419b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -166,6 +166,7 @@
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -403,6 +404,14 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
+ into the display overscan region. -->
+ <style name="Theme.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Theme for a light background with dark text on top. Set your activity
to this theme if you would like such an appearance. As with the
default theme, you should try to assume little more than that the
@@ -495,6 +504,14 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme_Light} that has no title bar and
+ no status bar and extending into the display overscan region. -->
+ <style name="Theme.Light.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Variant on {@link #Theme} that ensures the background is
completely black. This is useful for things like image viewers and
media players. If you want the normal (dark background) theme
@@ -516,6 +533,14 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of {@link #Theme_Black} that has no title bar and
+ no status bar and extending into the display overscan region. -->
+ <style name="Theme.Black.NoTitleBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Theme for windows that want to have the user's selected
wallpaper appear behind them (for API level 10 and lower). -->
<style name="Theme.Wallpaper">
@@ -1010,6 +1035,7 @@
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
@@ -1324,6 +1350,7 @@
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
<item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
<item name="windowShowWallpaper">false</item>
@@ -1563,6 +1590,14 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of the holographic (dark) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. -->
+ <style name="Theme.Holo.NoActionBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Variant of the holographic (light) theme with no action bar. -->
<style name="Theme.Holo.Light.NoActionBar">
<item name="android:windowActionBar">false</item>
@@ -1576,6 +1611,14 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Variant of the holographic (light) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. -->
+ <style name="Theme.Holo.Light.NoActionBar.Overscan">
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowOverscan">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
+
<!-- Dialog themes for Holo -->
<eat-comment />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 4178cc4..71aa5e6 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -202,12 +202,17 @@
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
<style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
-
</style>
+
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
-
</style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
+ extending in to overscan region. -->
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Holo.NoActionBar.Overscan" >
+ </style>
+
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
<!-- Text styles -->
@@ -356,11 +361,14 @@
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
-
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
-
+ </style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
+ and extending in to overscan region-->
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
+ parent="Theme.Holo.Light.NoActionBar.Overscan" >
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
floating (not fill the entire screen), and puts a frame around its contents. You can set this
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 8cbf299..e94ddae 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1199,7 +1199,7 @@
* meshHeight+1 vertices down. The verts array is accessed in row-major
* order, so that the first meshWidth+1 vertices are distributed across the
* top of the bitmap from left to right. A more general version of this
- * methid is drawVertices().
+ * method is drawVertices().
*
* @param bitmap The bitmap to draw using the mesh
* @param meshWidth The number of columns in the mesh. Nothing is drawn if
@@ -1208,7 +1208,7 @@
* this is 0
* @param verts Array of x,y pairs, specifying where the mesh should be
* drawn. There must be at least
- * (meshWidth+1) * (meshHeight+1) * 2 + meshOffset values
+ * (meshWidth+1) * (meshHeight+1) * 2 + vertOffset values
* in the array
* @param vertOffset Number of verts elements to skip before drawing
* @param colors May be null. Specifies a color at each vertex, which is
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 8aac628..398f719 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -263,6 +263,16 @@
ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
}
+float DisplayList::getPivotX() {
+ updateMatrix();
+ return mPivotX;
+}
+
+float DisplayList::getPivotY() {
+ updateMatrix();
+ return mPivotY;
+}
+
void DisplayList::updateMatrix() {
if (mMatrixDirty) {
if (!mTransformMatrix) {
@@ -426,13 +436,8 @@
Caches::getInstance().eventMark(strlen(op->name()), op->name());
#endif
- if (deferredList) {
- drawGlStatus |= op->replay(renderer, dirty, flags,
- saveCount, level, mCaching, mMultipliedAlpha, *deferredList);
- } else {
- drawGlStatus |= op->replay(renderer, dirty, flags,
- saveCount, level, mCaching, mMultipliedAlpha);
- }
+ drawGlStatus |= op->replay(renderer, dirty, flags,
+ saveCount, level, mCaching, mMultipliedAlpha, deferredList);
logBuffer.writeCommand(level, op->name());
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index d06827d..86c9ec0 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -105,6 +105,10 @@
}
}
+ const char* getName() const {
+ return mName.string();
+ }
+
void setClipChildren(bool clipChildren) {
mClipChildren = clipChildren;
}
@@ -114,6 +118,11 @@
mStaticMatrix = new SkMatrix(*matrix);
}
+ // Can return NULL
+ SkMatrix* getStaticMatrix() {
+ return mStaticMatrix;
+ }
+
void setAnimationMatrix(SkMatrix* matrix) {
delete mAnimationMatrix;
if (matrix) {
@@ -131,10 +140,18 @@
}
}
+ float getAlpha() const {
+ return mAlpha;
+ }
+
void setHasOverlappingRendering(bool hasOverlappingRendering) {
mHasOverlappingRendering = hasOverlappingRendering;
}
+ bool hasOverlappingRendering() const {
+ return mHasOverlappingRendering;
+ }
+
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
@@ -147,6 +164,10 @@
}
}
+ float getTranslationX() const {
+ return mTranslationX;
+ }
+
void setTranslationY(float translationY) {
if (translationY != mTranslationY) {
mTranslationY = translationY;
@@ -159,6 +180,10 @@
}
}
+ float getTranslationY() const {
+ return mTranslationY;
+ }
+
void setRotation(float rotation) {
if (rotation != mRotation) {
mRotation = rotation;
@@ -171,6 +196,10 @@
}
}
+ float getRotation() const {
+ return mRotation;
+ }
+
void setRotationX(float rotationX) {
if (rotationX != mRotationX) {
mRotationX = rotationX;
@@ -183,6 +212,10 @@
}
}
+ float getRotationX() const {
+ return mRotationX;
+ }
+
void setRotationY(float rotationY) {
if (rotationY != mRotationY) {
mRotationY = rotationY;
@@ -195,6 +228,10 @@
}
}
+ float getRotationY() const {
+ return mRotationY;
+ }
+
void setScaleX(float scaleX) {
if (scaleX != mScaleX) {
mScaleX = scaleX;
@@ -207,6 +244,10 @@
}
}
+ float getScaleX() const {
+ return mScaleX;
+ }
+
void setScaleY(float scaleY) {
if (scaleY != mScaleY) {
mScaleY = scaleY;
@@ -219,6 +260,10 @@
}
}
+ float getScaleY() const {
+ return mScaleY;
+ }
+
void setPivotX(float pivotX) {
mPivotX = pivotX;
mMatrixDirty = true;
@@ -230,6 +275,8 @@
mPivotExplicitlySet = true;
}
+ ANDROID_API float getPivotX();
+
void setPivotY(float pivotY) {
mPivotY = pivotY;
mMatrixDirty = true;
@@ -241,6 +288,8 @@
mPivotExplicitlySet = true;
}
+ ANDROID_API float getPivotY();
+
void setCameraDistance(float distance) {
if (distance != mCameraDistance) {
mCameraDistance = distance;
@@ -253,6 +302,10 @@
}
}
+ float getCameraDistance() const {
+ return mCameraDistance;
+ }
+
void setLeft(int left) {
if (left != mLeft) {
mLeft = left;
@@ -263,6 +316,10 @@
}
}
+ float getLeft() const {
+ return mLeft;
+ }
+
void setTop(int top) {
if (top != mTop) {
mTop = top;
@@ -273,6 +330,10 @@
}
}
+ float getTop() const {
+ return mTop;
+ }
+
void setRight(int right) {
if (right != mRight) {
mRight = right;
@@ -283,6 +344,10 @@
}
}
+ float getRight() const {
+ return mRight;
+ }
+
void setBottom(int bottom) {
if (bottom != mBottom) {
mBottom = bottom;
@@ -293,6 +358,10 @@
}
}
+ float getBottom() const {
+ return mBottom;
+ }
+
void setLeftTop(int left, int top) {
if (left != mLeft || top != mTop) {
mLeft = left;
@@ -319,7 +388,7 @@
}
}
- void offsetLeftRight(int offset) {
+ void offsetLeftRight(float offset) {
if (offset != 0) {
mLeft += offset;
mRight += offset;
@@ -329,7 +398,7 @@
}
}
- void offsetTopBottom(int offset) {
+ void offsetTopBottom(float offset) {
if (offset != 0) {
mTop += offset;
mBottom += offset;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8e80647..1bae0ff 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -74,14 +74,11 @@
kOpLogFlag_JSON = 0x2 // TODO: add?
};
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha) = 0;
-
- // same as replay above, but draw operations will defer into the deferredList if possible
- // NOTE: colorfilters, paintfilters, shaders, shadow, and complex clips prevent deferral
+ // If a DeferredDisplayList is supplied, DrawOps will be stored until the list is flushed
+ // NOTE: complex clips and layers prevent deferral
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha,
- DeferredDisplayList& deferredList) = 0;
+ DeferredDisplayList* deferredList) = 0;
virtual void output(int level, uint32_t flags = 0) = 0;
@@ -96,22 +93,16 @@
virtual ~StateOp() {}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha) {
- applyState(renderer, saveCount);
- return DrawGlInfo::kStatusDone;
- }
-
/**
* State operations are applied directly to the renderer, but can cause the deferred drawing op
* list to flush
*/
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
status_t status = DrawGlInfo::kStatusDone;
- if (requiresDrawOpFlush()) {
+ if (deferredList && requiresDrawOpFlush()) {
// will be setting renderer state that affects ops in deferredList, so flush list first
- status |= deferredList.flush(renderer, dirty, flags, level);
+ status |= deferredList->flush(renderer, dirty, flags, level);
}
applyState(renderer, saveCount);
return status;
@@ -131,23 +122,14 @@
DrawOp(SkPaint* paint)
: mPaint(paint), mQuickRejected(false) {}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha) {
- if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
- return DrawGlInfo::kStatusDone;
- }
-
- return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
- }
-
/** Draw operations are stored in the deferredList with information necessary for playback */
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
return DrawGlInfo::kStatusDone;
}
- if (renderer.disallowDeferral()) {
+ if (!deferredList || renderer.disallowDeferral()) {
// dispatch draw immediately, since the renderer's state is too complex for deferral
return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
}
@@ -161,7 +143,7 @@
if (!renderer.storeDisplayState(state)) {
// op wasn't quick-rejected, so defer
- deferredList.add(this, renderer.disallowReorder());
+ deferredList->add(this, renderer.disallowReorder());
}
return DrawGlInfo::kStatusDone;
@@ -184,7 +166,6 @@
float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
-public:
/**
* Stores the relevant canvas state of the object between deferral and replay (if the canvas
* state supports being stored) See OpenGLRenderer::simpleClipAndState()
@@ -204,7 +185,20 @@
DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
- // default constructor for area, to be overridden in child constructor body
+ // Calculates bounds as smallest rect encompassing all points
+ // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
+ // subclass' constructor)
+ DrawBoundedOp(const float* points, int count, SkPaint* paint)
+ : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
+ for (int i = 2; i < count; i += 2) {
+ mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
+ mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
+ mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
+ mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
+ }
+ }
+
+ // default empty constructor for bounds, to be overridden in child constructor body
DrawBoundedOp(SkPaint* paint)
: DrawOp(paint) {}
@@ -740,11 +734,12 @@
}
};
-class DrawBitmapMeshOp : public DrawOp {
+class DrawBitmapMeshOp : public DrawBoundedOp {
public:
DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint)
- : DrawOp(paint), mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
+ : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
+ mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
mVertices(vertices), mColors(colors) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -873,10 +868,11 @@
virtual const char* name() { return "DrawRect"; }
};
-class DrawRectsOp : public DrawOp {
+class DrawRectsOp : public DrawBoundedOp {
public:
DrawRectsOp(const float* rects, int count, SkPaint* paint)
- : DrawOp(paint), mRects(rects), mCount(count) {}
+ : DrawBoundedOp(rects, count, paint),
+ mRects(rects), mCount(count) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
@@ -1022,13 +1018,8 @@
class DrawLinesOp : public DrawBoundedOp {
public:
DrawLinesOp(float* points, int count, SkPaint* paint)
- : DrawBoundedOp(paint), mPoints(points), mCount(count) {
- for (int i = 0; i < count; i += 2) {
- mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
- mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
- mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]);
- mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]);
- }
+ : DrawBoundedOp(points, count, paint),
+ mPoints(points), mCount(count) {
mLocalBounds.outset(strokeWidthOutset());
}
@@ -1199,26 +1190,23 @@
Functor* mFunctor;
};
-class DrawDisplayListOp : public DrawOp {
+class DrawDisplayListOp : public DrawBoundedOp {
public:
DrawDisplayListOp(DisplayList* displayList, int flags)
- : DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
+ : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
+ mDisplayList(displayList), mFlags(flags) {}
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
- uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
if (mDisplayList && mDisplayList->isRenderable()) {
- return mDisplayList->replay(renderer, dirty, mFlags, level + 1, &deferredList);
+ return mDisplayList->replay(renderer, dirty, mFlags, level + 1, deferredList);
}
return DrawGlInfo::kStatusDone;
}
+ // NOT USED, since replay is overridden
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
- bool caching, int multipliedAlpha) {
- if (mDisplayList && mDisplayList->isRenderable()) {
- return mDisplayList->replay(renderer, dirty, mFlags, level + 1);
- }
- return DrawGlInfo::kStatusDone;
- }
+ bool caching, int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
virtual void output(int level, uint32_t flags) {
OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d11558f..6b614a7 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -280,7 +280,7 @@
void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
if (!mSuppressTiling) {
mCaches.startTiling(clip.left, windowHeight - clip.bottom,
- clip.right - clip.left, clip.bottom - clip.top, opaque);
+ clip.right - clip.left, clip.bottom - clip.top, opaque);
}
}
@@ -1235,6 +1235,8 @@
// quick rejected
return true;
}
+ } else {
+ state.mBounds.set(currentClip);
}
state.mClip.set(currentClip);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4398642..f6593e0 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -191,17 +191,27 @@
public static final int AACObjectHE_PS = 29;
public static final int AACObjectELD = 39;
+ // from OMX_VIDEO_VP8LEVELTYPE
+ public static final int VP8Level_Version0 = 0x01;
+ public static final int VP8Level_Version1 = 0x02;
+ public static final int VP8Level_Version2 = 0x04;
+ public static final int VP8Level_Version3 = 0x08;
+
+ // from OMX_VIDEO_VP8PROFILETYPE
+ public static final int VP8ProfileMain = 0x01;
+
+
/**
* Defined in the OpenMAX IL specs, depending on the type of media
* this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
- * or OMX_VIDEO_MPEG4PROFILETYPE.
+ * OMX_VIDEO_MPEG4PROFILETYPE or OMX_VIDEO_VP8PROFILETYPE.
*/
public int profile;
/**
* Defined in the OpenMAX IL specs, depending on the type of media
* this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
- * or OMX_VIDEO_MPEG4LEVELTYPE.
+ * OMX_VIDEO_MPEG4LEVELTYPE or OMX_VIDEO_VP8LEVELTYPE.
*/
public int level;
};
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7bd9049..11f4180 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -948,7 +948,12 @@
private void setDataSource(String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
- File file = new File(path);
+ final Uri uri = Uri.parse(path);
+ if ("file".equals(uri.getScheme())) {
+ path = uri.getPath();
+ }
+
+ final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 493c168..24d9c39 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
- <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejeza kamili"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
<string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?"\n\n" Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Cheleza data yangu"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
@@ -32,7 +32,7 @@
<string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
- <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejeza..."</string>
- <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejeza kumekamilika"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Inaanza kurejesha..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Kurejesha kumekamilika"</string>
<string name="toast_timeout" msgid="5276598587087626877">"Muda wa uendeshaji umeisha"</string>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b85121e..66080f3 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.DUMP" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 79f9650..8d949a5 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -485,14 +485,12 @@
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
- throw new RuntimeException("Cannot swap buffers");
- }
+ boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglError();
finishGL();
- return true;
+ return status;
}
private FloatBuffer createMesh(int left, int top, float right, float bottom) {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index ceb8654..8e1773a 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -154,6 +154,13 @@
return Math.max(mMinAlpha, result);
}
+ private void updateAlphaFromOffset(View animView, boolean dismissable) {
+ if (FADE_OUT_DURING_SWIPE && dismissable) {
+ animView.setAlpha(getAlphaForOffset(animView));
+ }
+ invalidateGlobalRegion(animView);
+ }
+
// invalidate the view's own bounds all the way up the view hierarchy
public static void invalidateGlobalRegion(View view) {
invalidateGlobalRegion(
@@ -290,10 +297,7 @@
});
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
- animView.setAlpha(getAlphaForOffset(animView));
- }
- invalidateGlobalRegion(animView);
+ updateAlphaFromOffset(animView, canAnimViewBeDismissed);
}
});
anim.start();
@@ -307,10 +311,12 @@
anim.setDuration(duration);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
- if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
- animView.setAlpha(getAlphaForOffset(animView));
- }
- invalidateGlobalRegion(animView);
+ updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+ }
+ });
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
+ updateAlphaFromOffset(animView, canAnimViewBeDismissed);
}
});
anim.start();
@@ -347,10 +353,8 @@
}
}
setTranslation(mCurrAnimView, delta);
- if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
- mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
- }
- invalidateGlobalRegion(mCurrView);
+
+ updateAlphaFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
}
break;
case MotionEvent.ACTION_UP:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7b80abc..988951c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -149,9 +149,17 @@
}
}
public float getXVelocity() {
+ if (Float.isNaN(mVX)) {
+ Slog.v("FlingTracker", "warning: vx=NaN");
+ // XXX: should return 0
+ }
return mVX;
}
public float getYVelocity() {
+ if (Float.isNaN(mVY)) {
+ Slog.v("FlingTracker", "warning: vx=NaN");
+ // XXX: should return 0
+ }
return mVY;
}
public void recycle() {
@@ -284,6 +292,9 @@
|| ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) {
post(mStopAnimator);
}
+ } else {
+ Slog.v(TAG, "animationTick called with dtms=" + dtms + "; nothing to do (h="
+ + mExpandedHeight + " v=" + mVel + ")");
}
}
@@ -374,7 +385,7 @@
case MotionEvent.ACTION_MOVE:
final float h = rawY - mAbsPos[1] - mTouchOffset;
if (h > mPeekHeight) {
- if (mPeekAnimator != null && mPeekAnimator.isRunning()) {
+ if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
mPeekAnimator.cancel();
}
mJustPeeked = false;
@@ -505,7 +516,7 @@
public void setExpandedHeight(float height) {
if (DEBUG) LOG("setExpandedHeight(%.1f)", height);
mRubberbanding = false;
- if (mTimeAnimator.isRunning()) {
+ if (mTimeAnimator.isStarted()) {
post(mStopAnimator);
}
setExpandedHeightInternal(height);
@@ -519,6 +530,11 @@
}
public void setExpandedHeightInternal(float h) {
+ if (Float.isNaN(h)) {
+ Slog.v(TAG, "setExpandedHeightInternal: warning: h=NaN");
+ // XXX: should set h to 0
+ }
+
float fh = getFullHeight();
if (fh == 0) {
// Hmm, full height hasn't been computed yet
@@ -526,6 +542,7 @@
if (h < 0) h = 0;
if (!(mRubberbandingEnabled && (mTracking || mRubberbanding)) && h > fh) h = fh;
+
mExpandedHeight = h;
if (DEBUG) LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
@@ -548,6 +565,10 @@
}
public void setExpandedFraction(float frac) {
+ if (Float.isNaN(frac)) {
+ Slog.v(TAG, "setExpandedFraction: frac=NaN");
+ // XXX: set frac to 0 to defend
+ }
setExpandedHeight(getFullHeight() * frac);
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 88a0ef3..e1d9b73 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -20,11 +20,7 @@
import static android.view.View.MeasureSpec.getMode;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.*;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
@@ -2639,7 +2635,11 @@
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
- setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
+ setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
+ }
+
+ if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) {
+ setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9cb54a9..acbde9b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -101,55 +101,7 @@
import java.io.IOException;
import java.io.PrintWriter;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
@@ -353,10 +305,17 @@
PointerLocationView mPointerLocationView;
InputChannel mPointerLocationInputChannel;
- // The current size of the screen; really; (ir)regardless of whether the status
- // bar can be hidden or not
+ // The current size of the screen; really; extends into the overscan area of
+ // the screen and doesn't account for any system elements like the status bar.
+ int mOverscanScreenLeft, mOverscanScreenTop;
+ int mOverscanScreenWidth, mOverscanScreenHeight;
+ // The current visible size of the screen; really; (ir)regardless of whether the status
+ // bar can be hidden but not extending into the overscan area.
int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
+ // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate.
+ int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop;
+ int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight;
// The current size of the screen; these may be different than (0,0)-(dw,dh)
// if the status bar can't be hidden; in that case it effectively carves out
// that area of the display from all other windows.
@@ -455,6 +414,11 @@
int mPortraitRotation = 0; // default portrait rotation
int mUpsideDownRotation = 0; // "other" portrait rotation
+ int mOverscanLeft = 0;
+ int mOverscanTop = 0;
+ int mOverscanRight = 0;
+ int mOverscanBottom = 0;
+
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior = -1;
@@ -946,6 +910,9 @@
@Override
public void setInitialDisplaySize(Display display, int width, int height, int density) {
+ if (display.getDisplayId() != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
mDisplay = display;
int shortSize, longSize;
@@ -1056,6 +1023,16 @@
mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
}
+ @Override
+ public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
+ if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mOverscanLeft = left;
+ mOverscanTop = top;
+ mOverscanRight = right;
+ mOverscanBottom = bottom;
+ }
+ }
+
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
@@ -2388,7 +2365,7 @@
contentInset.set(mStableLeft, mStableTop,
availRight - mStableRight, availBottom - mStableBottom);
}
- } else if ((fl & FLAG_FULLSCREEN) != 0) {
+ } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
contentInset.setEmpty();
} else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
@@ -2407,20 +2384,64 @@
@Override
public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
int displayRotation) {
- mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
- mUnrestrictedScreenWidth = displayWidth;
- mUnrestrictedScreenHeight = displayHeight;
- mRestrictedScreenLeft = mRestrictedScreenTop = 0;
- mRestrictedScreenWidth = displayWidth;
- mRestrictedScreenHeight = displayHeight;
+ final int overscanLeft, overscanTop, overscanRight, overscanBottom;
+ if (isDefaultDisplay) {
+ switch (displayRotation) {
+ case Surface.ROTATION_90:
+ overscanLeft = mOverscanTop;
+ overscanTop = mOverscanRight;
+ overscanRight = mOverscanBottom;
+ overscanBottom = mOverscanLeft;
+ break;
+ case Surface.ROTATION_180:
+ overscanLeft = mOverscanRight;
+ overscanTop = mOverscanBottom;
+ overscanRight = mOverscanLeft;
+ overscanBottom = mOverscanTop;
+ break;
+ case Surface.ROTATION_270:
+ overscanLeft = mOverscanBottom;
+ overscanTop = mOverscanLeft;
+ overscanRight = mOverscanTop;
+ overscanBottom = mOverscanRight;
+ break;
+ default:
+ overscanLeft = mOverscanLeft;
+ overscanTop = mOverscanTop;
+ overscanRight = mOverscanRight;
+ overscanBottom = mOverscanBottom;
+ break;
+ }
+ } else {
+ overscanLeft = 0;
+ overscanTop = 0;
+ overscanRight = 0;
+ overscanBottom = 0;
+ }
+ mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
+ mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
+ mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
+ mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
+ mSystemLeft = 0;
+ mSystemTop = 0;
+ mSystemRight = displayWidth;
+ mSystemBottom = displayHeight;
+ mUnrestrictedScreenLeft = overscanLeft;
+ mUnrestrictedScreenTop = overscanTop;
+ mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
+ mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
+ mRestrictedScreenLeft = mUnrestrictedScreenLeft;
+ mRestrictedScreenTop = mUnrestrictedScreenTop;
+ mRestrictedScreenWidth = mUnrestrictedScreenWidth;
+ mRestrictedScreenHeight = mUnrestrictedScreenHeight;
mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft
- = mSystemLeft = mCurLeft = 0;
+ = mCurLeft = mUnrestrictedScreenLeft;
mDockTop = mContentTop = mStableTop = mStableFullscreenTop
- = mSystemTop = mCurTop = 0;
+ = mCurTop = mUnrestrictedScreenTop;
mDockRight = mContentRight = mStableRight = mStableFullscreenRight
- = mSystemRight = mCurRight = displayWidth;
+ = mCurRight = displayWidth - overscanRight;
mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom
- = mSystemBottom = mCurBottom = displayHeight;
+ = mCurBottom = displayHeight - overscanBottom;
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
@@ -2467,13 +2488,15 @@
mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
if (mNavigationBarOnBottom) {
// It's a system nav bar or a portrait screen; nav bar goes on bottom.
- int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
- mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
+ int top = displayHeight - overscanBottom
+ - mNavigationBarHeightForRotation[displayRotation];
+ mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
if (navVisible) {
mNavigationBar.showLw(true);
mDockBottom = mTmpNavigationFrame.top;
- mRestrictedScreenHeight = mDockBottom - mDockTop;
+ mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
+ mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
} else {
// We currently want to hide the navigation UI.
mNavigationBar.hideLw(true);
@@ -2486,13 +2509,15 @@
}
} else {
// Landscape screen; nav bar goes to the right.
- int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
- mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
+ int left = displayWidth - overscanRight
+ - mNavigationBarWidthForRotation[displayRotation];
+ mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
if (navVisible) {
mNavigationBar.showLw(true);
mDockRight = mTmpNavigationFrame.left;
- mRestrictedScreenWidth = mDockRight - mDockLeft;
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
} else {
// We currently want to hide the navigation UI.
mNavigationBar.hideLw(true);
@@ -2524,8 +2549,8 @@
// apply any navigation bar insets
pf.left = df.left = mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
- pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
+ pf.right = df.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+ pf.bottom = df.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
vf.left = mStableLeft;
vf.top = mStableTop;
vf.right = mStableRight;
@@ -2685,12 +2710,12 @@
setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
} else {
// Give the window full screen.
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
pf.right = df.right = cf.right
- = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ = mOverscanScreenLeft + mOverscanScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ = mOverscanScreenTop + mOverscanScreenHeight;
}
} else if (attrs.type == TYPE_INPUT_METHOD) {
pf.left = df.left = cf.left = vf.left = mDockLeft;
@@ -2729,33 +2754,44 @@
pf.top = df.top = mUnrestrictedScreenTop;
pf.right = df.right = hasNavBar
? mRestrictedScreenLeft+mRestrictedScreenWidth
- : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = hasNavBar
? mRestrictedScreenTop+mRestrictedScreenHeight
- : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
}
+ } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure
+ // unrestricted area.
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
} else if (mCanHideNavigationBar
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
// Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
+ // application extend into the unrestricted overscan screen area. We
// only do this for application windows to ensure no window that
// can be above the nav bar can do this.
- pf.left = df.left = mUnrestrictedScreenLeft;
- pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
} else {
- pf.left = df.left = mRestrictedScreenLeft;
- pf.top = df.top = mRestrictedScreenTop;
- pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
- pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
+ pf.left = df.left = mRestrictedOverscanScreenLeft;
+ pf.top = df.top = mRestrictedOverscanScreenTop;
+ pf.right = df.right = mRestrictedOverscanScreenLeft
+ + mRestrictedOverscanScreenWidth;
+ pf.bottom = df.bottom = mRestrictedOverscanScreenTop
+ + mRestrictedOverscanScreenHeight;
}
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
@@ -2793,10 +2829,10 @@
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
pf.right = df.right = cf.right = hasNavBar
? mRestrictedScreenLeft+mRestrictedScreenWidth
- : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = cf.bottom = hasNavBar
? mRestrictedScreenTop+mRestrictedScreenHeight
- : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
@@ -2807,8 +2843,8 @@
// The navigation bar has Real Ultimate Power.
pf.left = df.left = mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
if (DEBUG_LAYOUT) {
Log.v(TAG, String.format(
"Laying out navigation bar window: (%d,%d - %d,%d)",
@@ -2818,18 +2854,37 @@
|| attrs.type == TYPE_BOOT_PROGRESS)
&& ((fl & FLAG_FULLSCREEN) != 0)) {
// Fullscreen secure system overlays get what they ask for.
- pf.left = df.left = mUnrestrictedScreenLeft;
- pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
} else if (attrs.type == TYPE_BOOT_PROGRESS
|| attrs.type == TYPE_UNIVERSE_BACKGROUND) {
// Boot progress screen always covers entire display.
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
+ pf.right = df.right = cf.right = mOverscanScreenLeft + mOverscanScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ = mOverscanScreenTop + mOverscanScreenHeight;
+ } else if (attrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
+ // The wallpaper mostly goes into the overscan region.
+ pf.left = df.left = cf.left = mRestrictedOverscanScreenLeft;
+ pf.top = df.top = cf.top = mRestrictedOverscanScreenTop;
+ pf.right = df.right = cf.right
+ = mRestrictedOverscanScreenLeft + mRestrictedOverscanScreenWidth;
+ pf.bottom = df.bottom = cf.bottom
+ = mRestrictedOverscanScreenTop + mRestrictedOverscanScreenHeight;
+ } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure
+ // unrestricted area.
+ pf.left = df.left = cf.left = mOverscanScreenLeft;
+ pf.top = df.top = cf.top = mOverscanScreenTop;
+ pf.right = df.right = cf.right
+ = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = cf.bottom
+ = mOverscanScreenTop + mOverscanScreenHeight;
} else if (mCanHideNavigationBar
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
@@ -2843,9 +2898,9 @@
// what the screen would be if only laying out to hide the nav bar.
pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.right = df.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -4661,6 +4716,22 @@
pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
pw.print(" mScreenOnFully="); pw.print(mScreenOnFully);
pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled);
+ pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
+ pw.print(","); pw.print(mOverscanScreenTop);
+ pw.print(") "); pw.print(mOverscanScreenWidth);
+ pw.print("x"); pw.println(mOverscanScreenHeight);
+ if (mOverscanLeft != 0 || mOverscanTop != 0
+ || mOverscanRight != 0 || mOverscanBottom != 0) {
+ pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
+ pw.print(" top="); pw.print(mOverscanTop);
+ pw.print(" right="); pw.print(mOverscanRight);
+ pw.print(" bottom="); pw.println(mOverscanBottom);
+ }
+ pw.print(prefix); pw.print("mRestrictedOverscanScreen=(");
+ pw.print(mRestrictedOverscanScreenLeft);
+ pw.print(","); pw.print(mRestrictedOverscanScreenTop);
+ pw.print(") "); pw.print(mRestrictedOverscanScreenWidth);
+ pw.print("x"); pw.println(mRestrictedOverscanScreenHeight);
pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
pw.print(","); pw.print(mUnrestrictedScreenTop);
pw.print(") "); pw.print(mUnrestrictedScreenWidth);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 27d808b..a0a5f5a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -136,6 +136,16 @@
mAppWidgetHost = new AppWidgetHost(
context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
mAppWidgetHost.setUserId(mUserId);
+
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ mDisabledFeatures = getDisabledFeatures(dpm);
+ mCameraDisabled = dpm.getCameraDisabled(null);
+ }
+
+ mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+
cleanupAppWidgetIds();
mAppWidgetManager = AppWidgetManager.getInstance(mContext);
@@ -143,14 +153,6 @@
mViewStateManager = new KeyguardViewStateManager(this);
- DevicePolicyManager dpm =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- mDisabledFeatures = getDisabledFeatures(dpm);
- mCameraDisabled = dpm.getCameraDisabled(null);
- }
-
- mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
@@ -172,19 +174,21 @@
mCleanupAppWidgetsOnBootCompleted = true;
return;
}
- // Clean up appWidgetIds that are bound to lockscreen, but not actually used
- // This is only to clean up after another bug: we used to not call
- // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
- // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
- // that are triggered by deleteAppWidgetId, which is why we're doing this
- int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
- int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
- for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
- int appWidgetId = appWidgetIdsBoundToHost[i];
- if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
- Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
- + appWidgetId);
- mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+ // Clean up appWidgetIds that are bound to lockscreen, but not actually used
+ // This is only to clean up after another bug: we used to not call
+ // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
+ // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
+ // that are triggered by deleteAppWidgetId, which is why we're doing this
+ int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
+ int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
+ for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
+ int appWidgetId = appWidgetIdsBoundToHost[i];
+ if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
+ Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
+ + appWidgetId);
+ mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ }
}
}
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index c31cde7..6d817a1 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
package com.android.server;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -32,7 +31,6 @@
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import android.app.Activity;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -88,7 +86,6 @@
import android.security.Credentials;
import android.security.KeyStore;
import android.text.TextUtils;
-import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -3336,7 +3333,10 @@
@Override
public boolean updateLockdownVpn() {
- enforceSystemUid();
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
+ return false;
+ }
// Tear down existing lockdown if profile was removed
mLockdownEnabled = LockdownVpnTracker.isEnabled();
@@ -3387,11 +3387,4 @@
throw new IllegalStateException("Unavailable in lockdown mode");
}
}
-
- private static void enforceSystemUid() {
- final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID) {
- throw new SecurityException("Only available to AID_SYSTEM");
- }
- }
}
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/java/com/android/server/IdleMaintenanceService.java
new file mode 100644
index 0000000..a7442f6
--- /dev/null
+++ b/services/java/com/android/server/IdleMaintenanceService.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 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.server;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * This service observes the device state and when applicable sends
+ * broadcasts at the beginning and at the end of a period during which
+ * observers can perform idle maintenance tasks. Typical use of the
+ * idle maintenance is to perform somehow expensive tasks that can be
+ * postponed to a moment when they will not degrade user experience.
+ *
+ * The current implementation is very simple. The start of a maintenance
+ * window is announced if: the screen is off or showing a dream AND the
+ * battery level is more than twenty percent AND at least one hour passed
+ * since the screen went off or a dream started (i.e. since the last user
+ * activity).
+ *
+ * The end of a maintenance window is announced only if: a start was
+ * announced AND the screen turned on or a dream was stopped.
+ */
+public class IdleMaintenanceService extends BroadcastReceiver {
+
+ private final boolean DEBUG = false;
+
+ private static final String LOG_TAG = IdleMaintenanceService.class.getSimpleName();
+
+ private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
+
+ private static final int MIN_IDLE_MAINTENANCE_START_BATTERY_LEVEL = 20; // percent
+
+ private static final long MIN_IDLE_MAINTENANCE_START_USER_INACTIVITY = 60 * 60 * 1000; // 1 hour
+
+ private final Intent mIdleMaintenanceStartIntent =
+ new Intent(Intent.ACTION_IDLE_MAINTENANCE_START);
+
+ private final Intent mIdleMaintenanceEndIntent =
+ new Intent(Intent.ACTION_IDLE_MAINTENANCE_END);
+
+ private final Context mContext;
+
+ private final WakeLock mWakeLock;
+
+ private final Handler mHandler;
+
+ private final Calendar mTempCalendar = Calendar.getInstance();
+
+ private final Calendar mLastIdleMaintenanceStartTime = Calendar.getInstance();
+
+ private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
+
+ private int mBatteryLevel;
+
+ private boolean mIdleMaintenanceStarted;
+
+ public IdleMaintenanceService(Context context) {
+ mContext = context;
+
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
+
+ mHandler = new Handler(mContext.getMainLooper());
+
+ // Move one day back so we can run maintenance the first day after starting.
+ final int prevDayOfYear = mLastIdleMaintenanceStartTime.get(Calendar.DAY_OF_YEAR) - 1;
+ mLastIdleMaintenanceStartTime.set(Calendar.DAY_OF_YEAR, prevDayOfYear);
+
+ register(mContext.getMainLooper());
+ }
+
+ public void register(Looper looper) {
+ IntentFilter intentFilter = new IntentFilter();
+
+ // Battery actions.
+ intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+
+ // Screen actions.
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+
+ // Dream actions.
+ intentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
+ intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
+
+ mContext.registerReceiverAsUser(this, UserHandle.ALL,
+ intentFilter, null, new Handler(looper));
+ }
+
+ private void updateIdleMaintenanceState() {
+ if (mIdleMaintenanceStarted) {
+ // Idle maintenance can be interrupted only by
+ // a change of the device state.
+ if (!deviceStatePermitsIdleMaintenance()) {
+ mIdleMaintenanceStarted = false;
+ sendIdleMaintenanceEndIntent();
+ }
+ } else if (deviceStatePermitsIdleMaintenance()
+ && lastUserActivityPermitsIdleMaintenanceStart()
+ && lastRunPermitsIdleMaintenanceStart()) {
+ mIdleMaintenanceStarted = true;
+ mLastIdleMaintenanceStartTime.setTimeInMillis(System.currentTimeMillis());
+ sendIdleMaintenanceStartIntent();
+ }
+ }
+
+ private void sendIdleMaintenanceStartIntent() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Broadcasting " + Intent.ACTION_IDLE_MAINTENANCE_START);
+ }
+ mWakeLock.acquire();
+ mContext.sendOrderedBroadcastAsUser(mIdleMaintenanceStartIntent, UserHandle.ALL,
+ null, this, mHandler, Activity.RESULT_OK, null, null);
+ }
+
+ private void sendIdleMaintenanceEndIntent() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Broadcasting " + Intent.ACTION_IDLE_MAINTENANCE_END);
+ }
+ mWakeLock.acquire();
+ mContext.sendOrderedBroadcastAsUser(mIdleMaintenanceEndIntent, UserHandle.ALL,
+ null, this, mHandler, Activity.RESULT_OK, null, null);
+ }
+
+ private boolean deviceStatePermitsIdleMaintenance() {
+ return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
+ && mBatteryLevel > MIN_IDLE_MAINTENANCE_START_BATTERY_LEVEL);
+ }
+
+ private boolean lastUserActivityPermitsIdleMaintenanceStart() {
+ return (SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
+ > MIN_IDLE_MAINTENANCE_START_USER_INACTIVITY);
+ }
+
+ private boolean lastRunPermitsIdleMaintenanceStart() {
+ Calendar now = mTempCalendar;
+ // Not setting the Locale since we do not care of locale
+ // specific properties such as the first day of the week.
+ now.setTimeZone(TimeZone.getDefault());
+ now.setTimeInMillis(System.currentTimeMillis());
+
+ Calendar lastRun = mLastIdleMaintenanceStartTime;
+ // Not setting the Locale since we do not care of locale
+ // specific properties such as the first day of the week.
+ lastRun.setTimeZone(TimeZone.getDefault());
+
+ return now.get(Calendar.DAY_OF_YEAR) != lastRun.get(Calendar.DAY_OF_YEAR);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, intent.getAction());
+ }
+ String action = intent.getAction();
+ if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+ final int maxBatteryLevel = intent.getExtras().getInt(BatteryManager.EXTRA_SCALE);
+ final int currBatteryLevel = intent.getExtras().getInt(BatteryManager.EXTRA_LEVEL);
+ mBatteryLevel = (int) (((float) maxBatteryLevel / 100) * currBatteryLevel);
+ } else if (Intent.ACTION_SCREEN_ON.equals(action)
+ || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
+ mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
+ } else if (Intent.ACTION_SCREEN_OFF.equals(action)
+ || Intent.ACTION_DREAMING_STARTED.equals(action)) {
+ mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
+ } else if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)
+ || Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+ mWakeLock.release();
+ return;
+ }
+ updateIdleMaintenanceState();
+ }
+}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 13bf39f..9f2685b 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -26,6 +26,7 @@
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
+import android.app.INotificationListener;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.PendingIntent;
@@ -151,6 +152,7 @@
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
+ // used as a mutex for access to all active notifications & listeners
private final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
@@ -161,6 +163,8 @@
private final AppOpsManager mAppOps;
+ private ArrayList<NotificationListenerInfo> mListeners = new ArrayList<NotificationListenerInfo>();
+
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -174,6 +178,38 @@
private static final String TAG_PACKAGE = "package";
private static final String ATTR_NAME = "name";
+ private class NotificationListenerInfo implements DeathRecipient {
+ INotificationListener listener;
+ int userid;
+ public NotificationListenerInfo(INotificationListener listener, int userid) {
+ this.listener = listener;
+ this.userid = userid;
+ }
+
+ public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
+ if (this.userid != sbn.getUserId()) return;
+ try {
+ listener.onNotificationPosted(sbn);
+ } catch (RemoteException ex) {
+ // not there?
+ }
+ }
+
+ public void notifyRemovedIfUserMatch(StatusBarNotification sbn) {
+ if (this.userid != sbn.getUserId()) return;
+ try {
+ listener.onNotificationRemoved(sbn);
+ } catch (RemoteException ex) {
+ // not there?
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ unregisterListener(this.listener, this.userid);
+ }
+ }
+
private static class Archive {
static final int BUFFER_SIZE = 1000;
ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
@@ -406,6 +442,56 @@
return tmp;
}
+ @Override
+ public void registerListener(final INotificationListener listener, final int userid) {
+ checkCallerIsSystem();
+ synchronized (mNotificationList) {
+ try {
+ NotificationListenerInfo info = new NotificationListenerInfo(listener, userid);
+ listener.asBinder().linkToDeath(info, 0);
+ mListeners.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ @Override
+ public void unregisterListener(INotificationListener listener, int userid) {
+ checkCallerIsSystem();
+ synchronized (mNotificationList) {
+ final int N = mListeners.size();
+ for (int i=N-1; i>=0; i--) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (info.listener == listener && info.userid == userid) {
+ mListeners.remove(listener);
+ }
+ }
+ }
+ }
+
+ private void notifyPostedLocked(NotificationRecord n) {
+ final StatusBarNotification sbn = n.sbn;
+ for (final NotificationListenerInfo info : mListeners) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ info.notifyPostedIfUserMatch(sbn);
+ }});
+ }
+ }
+
+ private void notifyRemovedLocked(NotificationRecord n) {
+ final StatusBarNotification sbn = n.sbn;
+ for (final NotificationListenerInfo info : mListeners) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ info.notifyRemovedIfUserMatch(sbn);
+ }});
+ }
+ }
+
public static final class NotificationRecord
{
final StatusBarNotification sbn;
@@ -1165,6 +1251,8 @@
// finally, keep some of this information around for later use
mArchive.record(n);
+
+ notifyPostedLocked(r);
} else {
Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
if (old != null && old.statusBarKey != null) {
@@ -1175,6 +1263,8 @@
finally {
Binder.restoreCallingIdentity(identity);
}
+
+ notifyRemovedLocked(r);
}
return; // do not play sounds, show lights, etc. for invalid notifications
}
@@ -1341,6 +1431,7 @@
Binder.restoreCallingIdentity(identity);
}
r.statusBarKey = null;
+ notifyRemovedLocked(r);
}
// sound
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 39ee47e..949c2ed 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -255,7 +255,7 @@
}
ActivityManagerService.setSystemProcess();
-
+
Slog.i(TAG, "User Service");
ServiceManager.addService(Context.USER_SERVICE,
UserManagerService.getInstance());
@@ -736,6 +736,13 @@
reportWtf("starting DreamManagerService", e);
}
}
+
+ try {
+ Slog.i(TAG, "IdleMaintenanceService");
+ new IdleMaintenanceService(context);
+ } catch (Throwable e) {
+ reportWtf("starting IdleMaintenanceService", e);
+ }
}
// Before things start rolling, be sure we have decided whether
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c1b406e..f2d401f 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -471,6 +471,7 @@
void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
if (inHistory && !finishing) {
if (task != null) {
+ task.removeActivity(this);
task.numActivities--;
}
if (newTask != null) {
@@ -505,6 +506,7 @@
inHistory = false;
if (task != null && !finishing) {
task.numActivities--;
+ task = null;
}
clearOptionsLocked();
}
@@ -539,7 +541,7 @@
ActivityResult r = new ActivityResult(from, resultWho,
requestCode, resultCode, resultData);
if (results == null) {
- results = new ArrayList();
+ results = new ArrayList<ResultInfo>();
}
results.add(r);
}
@@ -950,6 +952,8 @@
StringBuilder sb = new StringBuilder(128);
sb.append("ActivityRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" t");
+ sb.append(task.taskId);
sb.append(" u");
sb.append(userId);
sb.append(' ');
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c54cdaa..a18a0d1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -54,6 +54,7 @@
import android.graphics.Bitmap.Config;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -66,6 +67,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import java.io.FileDescriptor;
@@ -75,6 +77,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* State and management of a single stack of activities.
@@ -98,7 +101,8 @@
static final boolean DEBUG_APP = false;
static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
-
+ static final boolean VALIDATE_TASK_REPLACE = true;
+
// How long we wait until giving up on the last activity telling us it
// is idle.
static final int IDLE_TIMEOUT = 10*1000;
@@ -137,7 +141,10 @@
// Set to false to disable the preview that is shown while a new activity
// is being started.
static final boolean SHOW_APP_STARTING_PREVIEW = true;
-
+
+ static final boolean FORWARD_ITERATOR = false;
+ static final boolean REVERSE_ITERATOR = true;
+
enum ActivityState {
INITIALIZING,
RESUMED,
@@ -154,7 +161,7 @@
final boolean mMainStack;
final Context mContext;
-
+
/**
* The back history of all previous (and possibly still
* running) activities. It contains #ActivityRecord objects.
@@ -162,6 +169,17 @@
private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
/**
+ * The back history of all previous (and possibly still
+ * running) activities. It contains #TaskRecord objects.
+ */
+ private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
+
+ /**
+ * Mapping from taskId to TaskRecord
+ */
+ private SparseArray<TaskRecord> mTaskIdToTaskRecord = new SparseArray<TaskRecord>();
+
+ /**
* Used for validating app tokens with window manager.
*/
final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
@@ -289,6 +307,12 @@
*/
boolean mDismissKeyguardOnNextActivity = false;
+ /** So we don't have to keep constructing a new object for utility non-nested use. */
+ final ActivityIterator mTmpActivityIterator = new ActivityIterator(FORWARD_ITERATOR, true);
+
+ /** So we don't have to keep constructing a new object for utility non-nested use. */
+ final TaskIterator mTmpTaskIterator = new TaskIterator();
+
/**
* Save the most recent screenshot for reuse. This keeps Recents from taking two identical
* screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
@@ -508,30 +532,69 @@
}
final ActivityRecord isInStackLocked(IBinder token) {
+ ActivityRecord newAr = newIsInStackLocked(token);
+
ActivityRecord r = ActivityRecord.forToken(token);
if (mHistory.contains(r)) {
+ if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
+ "isInStackLocked: mismatch: newAr=" + newAr + " r=" + r);
return r;
}
+ if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+ "isInStackLocked: mismatch: newAr!=null");
+ return null;
+ }
+
+ final ActivityRecord newIsInStackLocked(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ final TaskRecord task = r.task;
+ if (mTaskHistory.contains(task) && task.mActivities.contains(r)) {
+ return r;
+ }
+ }
return null;
}
int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+ int newTaskId = newGetTaskForActivityLocked(token, onlyRoot);
+
TaskRecord lastTask = null;
final int N = mHistory.size();
for (int i = 0; i < N; i++) {
ActivityRecord r = mHistory.get(i);
if (r.appToken == token) {
if (!onlyRoot || lastTask != r.task) {
+ if (VALIDATE_TASK_REPLACE && newTaskId != r.task.taskId) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch: new=" + newTaskId
+ + " taskId=" + r.task.taskId);
return r.task.taskId;
}
+ if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch: newTaskId=" + newTaskId + " not -1.");
return -1;
}
lastTask = r.task;
}
+ if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch at end: newTaskId=" + newTaskId + " not -1.");
return -1;
}
+ int newGetTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+ final ActivityRecord r = ActivityRecord.forToken(token);
+ if (r == null) {
+ return -1;
+ }
+ final TaskRecord task = r.task;
+ switch (task.mActivities.indexOf(r)) {
+ case -1: return -1;
+ case 0: return task.taskId;
+ default: return onlyRoot ? -1 : task.taskId;
+ }
+ }
+
private final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -624,17 +687,29 @@
* @return whether there are any activities for the specified user.
*/
final boolean switchUserLocked(int userId, UserStartedState uss) {
+ if (VALIDATE_TOKENS) {
+ validateAppTokensLocked();
+ }
+ final boolean newResult = newSwitchUserLocked(userId, uss);
+
mCurrentUser = userId;
mStartingUsers.add(uss);
// Only one activity? Nothing to do...
- if (mHistory.size() < 2)
+ if (mHistory.size() < 2) {
+ if (VALIDATE_TASK_REPLACE && newResult) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + false);
return false;
+ }
boolean haveActivities = false;
// Check if the top activity is from the new user.
ActivityRecord top = mHistory.get(mHistory.size() - 1);
- if (top.userId == userId) return true;
+ if (top.userId == userId) {
+ if (VALIDATE_TASK_REPLACE && !newResult) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + true);
+ return true;
+ }
// Otherwise, move the user's activities to the top.
int N = mHistory.size();
int i = 0;
@@ -651,7 +726,44 @@
}
}
// Transition from the old top to the new top
+ if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+ "switchUserLocked: calling resumeTopActivity " + top);
resumeTopActivityLocked(top);
+ if (VALIDATE_TASK_REPLACE && (newResult != haveActivities)) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + haveActivities);
+ return haveActivities;
+ }
+
+ /*
+ * Move the activities around in the stack to bring a user to the foreground.
+ * @return whether there are any activities for the specified user.
+ */
+ final boolean newSwitchUserLocked(int userId, UserStartedState uss) {
+// mStartingUsers.add(uss);
+ if (mCurrentUser == userId) {
+ return true;
+ }
+ mCurrentUser = userId;
+
+ // Move userId's tasks to the top.
+ boolean haveActivities = false;
+ TaskRecord task = null;
+ int index = mTaskHistory.size();
+ for (int i = 0; i < index; ++i) {
+ task = mTaskHistory.get(i);
+ if (task.userId == userId) {
+ haveActivities = true;
+ mTaskHistory.remove(i);
+ mTaskHistory.add(task);
+ --index;
+ }
+ }
+
+ // task is now the original topmost TaskRecord. Transition from the old top to the new top.
+ ActivityRecord top = task != null ? task.getTopActivity() : null;
+ if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+ "newSwitchUserLocked: would call resumeTopActivity " + top);
+// resumeTopActivityLocked(top);
return haveActivities;
}
@@ -889,6 +1001,9 @@
mGoingToSleep.release();
}
// Ensure activities are no longer sleeping.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
for (int i=mHistory.size()-1; i>=0; i--) {
ActivityRecord r = mHistory.get(i);
r.setSleeping(false);
@@ -933,6 +1048,9 @@
// Make sure any stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
for (int i=mHistory.size()-1; i>=0; i--) {
ActivityRecord r = mHistory.get(i);
if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
@@ -1077,6 +1195,9 @@
ActivityRecord r = null;
synchronized (mService) {
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
int index = indexOfTokenLocked(token);
if (index >= 0) {
r = mHistory.get(index);
@@ -1094,6 +1215,9 @@
ActivityRecord r = null;
synchronized (mService) {
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
int index = indexOfTokenLocked(token);
if (index >= 0) {
r = mHistory.get(index);
@@ -1306,6 +1430,9 @@
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
final int count = mHistory.size();
int i = count-1;
while (mHistory.get(i) != top) {
@@ -1868,6 +1995,7 @@
Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
here);
}
+ r.task.addActivityToTop(r);
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
@@ -1907,6 +2035,7 @@
here.fillInStackTrace();
Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
}
+ r.task.addActivityToTop(r);
mHistory.add(addPos, r);
r.putInHistory();
r.frontOfTask = newTask;
@@ -1986,6 +2115,9 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
}
final void validateAppTokensLocked() {
@@ -2107,8 +2239,8 @@
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
- target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
- null, false);
+ target.setTask(createTaskRecord(mService.mCurTask, target.info, null,
+ false), null, false);
target.task.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
@@ -2172,8 +2304,7 @@
// like these are all in the reply chain.
replyChainEnd = targetI+1;
while (replyChainEnd < mHistory.size() &&
- (mHistory.get(
- replyChainEnd)).task == task) {
+ (mHistory.get(replyChainEnd)).task == task) {
replyChainEnd++;
}
replyChainEnd--;
@@ -2346,6 +2477,9 @@
}
}
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
return taskTop;
}
@@ -3011,7 +3145,7 @@
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
- r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+ r.setTask(createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
@@ -3075,7 +3209,7 @@
N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
- : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+ : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
@@ -4160,6 +4294,9 @@
here.fillInStackTrace();
Slog.i(TAG, "Removing activity " + r + " from stack");
}
+ if (r.task != null) {
+ r.task.removeActivity(r);
+ }
mHistory.remove(r);
r.takeFromHistory();
removeTimeoutsForActivityLocked(r);
@@ -5169,4 +5306,185 @@
return starting;
}
+
+ void verifyActivityRecords() {
+ /* Until we have activity movement implemented for tasks just do the simple test
+ ActivityIterator iterator = new ActivityIterator();
+ int i;
+ int N = mHistory.size();
+ for (i = 0; i < N && iterator.hasNext(); ++i) {
+ ActivityRecord r1 = mHistory.get(i);
+ ActivityRecord r2 = iterator.next();
+ if (r1 != r2) {
+ break;
+ }
+ }
+ if (i != N || iterator.hasNext()) {
+ Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+ + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+ } */
+ // Simple test
+ ActivityIterator iterator = new ActivityIterator();
+ while (iterator.hasNext()) {
+ ActivityRecord r = iterator.next();
+ if (!mHistory.contains(r)) {
+ break;
+ }
+ }
+ if (iterator.size() != mHistory.size() || iterator.hasNext()) {
+ Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+ + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+ }
+ }
+
+ private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ boolean toTop) {
+ TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);
+ if (oldTask != null) {
+ Slog.w(TAG, "createTaskRecord: Reusing taskId=" + taskId + " without removing");
+ mTaskHistory.remove(oldTask);
+ }
+ TaskRecord task = new TaskRecord(taskId, info, intent);
+ mTaskIdToTaskRecord.put(taskId, task);
+ if (toTop) {
+ mTaskHistory.add(task);
+ } else {
+ mTaskHistory.add(0, task);
+ }
+ return task;
+ }
+
+ class TaskIterator implements Iterator<TaskRecord> {
+ private int mCur;
+ private boolean mReverse;
+
+ TaskIterator() {
+ this(FORWARD_ITERATOR);
+ }
+
+ TaskIterator(boolean reverse) {
+ reset(reverse);
+ }
+
+ public void reset(boolean reverse) {
+ mReverse = reverse;
+ mCur = reverse ? mTaskHistory.size() - 1 : 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskHistory.size();
+ }
+
+ @Override
+ public TaskRecord next() {
+ if (hasNext()) {
+ TaskRecord task = mTaskHistory.get(mCur);
+ mCur += (mReverse ? -1 : 1);
+ return task;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ class ActivityIterator implements Iterator<ActivityRecord> {
+ final TaskIterator mIterator;
+ boolean mReverse;
+ int mCur;
+ TaskRecord mTaskRecord;
+ final boolean mSkipFinishing;
+
+ public ActivityIterator() {
+ this(FORWARD_ITERATOR);
+ }
+
+ public ActivityIterator(boolean reverse) {
+ this(reverse, false);
+ }
+
+ public ActivityIterator(boolean reverse, boolean skipFinishing) {
+ mSkipFinishing = skipFinishing;
+ mIterator = new TaskIterator();
+ reset(reverse);
+ }
+
+ public void reset(boolean reverse) {
+ mReverse = reverse;
+ mIterator.reset(reverse);
+ getNextTaskRecord();
+ }
+
+ private void getNextTaskRecord() {
+ if (mIterator.hasNext()) {
+ mTaskRecord = mIterator.next();
+ mCur = mReverse ? mTaskRecord.mActivities.size() - 1 : 0;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mTaskRecord == null) {
+ return false;
+ }
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskRecord.mActivities.size();
+ }
+
+ @Override
+ public ActivityRecord next() {
+ while (hasNext()) {
+ ActivityRecord r = mTaskRecord.mActivities.get(mCur);
+ mCur += mReverse ? -1 : 1;
+ if (!hasNext()) {
+ getNextTaskRecord();
+ }
+ if (mSkipFinishing && r.finishing) {
+ continue;
+ }
+ return r;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ int size() {
+ int size = 0;
+ final TaskIterator iterator = new TaskIterator();
+ while (iterator.hasNext()) {
+ size += iterator.next().mActivities.size();
+ }
+ return size;
+ }
+
+ ActivityRecord peek() {
+ if (mTaskRecord != null && mCur >= 0 && mCur < mTaskRecord.mActivities.size()) {
+ return mTaskRecord.mActivities.get(mCur);
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < mTaskHistory.size(); ++i) {
+ final TaskRecord task = mTaskHistory.get(i);
+ sb.append("task_").append(i).append("-").append(task.mActivities).append(" ");
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 1bae9ca..347aa7d 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.ArrayList;
class TaskRecord extends ThumbnailHolder {
final int taskId; // Unique identifier for this task.
@@ -39,7 +40,11 @@
String stringName; // caching of toString() result.
int userId; // user for which this task was created
-
+
+ int numFullscreen; // Number of fullscreen activities.
+
+ final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
+
TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
taskId = _taskId;
affinity = info.taskAffinity;
@@ -104,12 +109,49 @@
userId = UserHandle.getUserId(info.applicationInfo.uid);
}
}
-
+
+ ActivityRecord getTopActivity() {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.finishing) {
+ continue;
+ }
+ return r;
+ }
+ return null;
+ }
+
+ void addActivityAtBottom(ActivityRecord r) {
+ if (!mActivities.remove(r) && r.fullscreen) {
+ // Was not previously in list.
+ numFullscreen++;
+ }
+ mActivities.add(0, r);
+ }
+
+ void addActivityToTop(ActivityRecord r) {
+ if (!mActivities.remove(r) && r.fullscreen) {
+ // Was not previously in list.
+ numFullscreen++;
+ }
+ mActivities.add(r);
+ }
+
+ /** @return true if this was the last activity in the task */
+ boolean removeActivity(ActivityRecord r) {
+ if (mActivities.remove(r) && r.fullscreen) {
+ // Was previously in list.
+ numFullscreen--;
+ }
+ return mActivities.size() == 0;
+ }
+
void dump(PrintWriter pw, String prefix) {
if (numActivities != 0 || rootWasReset || userId != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
pw.print(" rootWasReset="); pw.print(rootWasReset);
- pw.print(" userId="); pw.println(userId);
+ pw.print(" userId="); pw.print(userId);
+ pw.print(" numFullscreen="); pw.println(numFullscreen);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
@@ -136,6 +178,7 @@
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
}
+ pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
if (!askedCompatMode) {
pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
}
@@ -146,6 +189,7 @@
pw.print((getInactiveDuration()/1000)); pw.println("s)");
}
+ @Override
public String toString() {
if (stringName != null) {
return stringName;
@@ -156,19 +200,21 @@
sb.append(" #");
sb.append(taskId);
if (affinity != null) {
- sb.append(" A ");
+ sb.append(" A=");
sb.append(affinity);
} else if (intent != null) {
- sb.append(" I ");
+ sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
} else if (affinityIntent != null) {
- sb.append(" aI ");
+ sb.append(" aI=");
sb.append(affinityIntent.getComponent().flattenToShortString());
} else {
sb.append(" ??");
}
- sb.append(" U ");
+ sb.append(" U=");
sb.append(userId);
+ sb.append(" sz=");
+ sb.append(mActivities.size());
sb.append('}');
return stringName = sb.toString();
}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 813c9c7..17b0662 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -324,6 +324,18 @@
}
/**
+ * Sets the overscan insets for a particular display.
+ */
+ public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ display.setOverscan(left, top, right, bottom);
+ }
+ }
+ }
+
+ /**
* Called by the window manager to perform traversals while holding a
* surface flinger transaction.
*/
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 1583137..424ec36 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -143,6 +143,19 @@
}
}
+ public void setOverscan(int left, int top, int right, int bottom) {
+ mInfo.overscanLeft = left;
+ mInfo.overscanTop = top;
+ mInfo.overscanRight = right;
+ mInfo.overscanBottom = bottom;
+ if (mOverrideDisplayInfo != null) {
+ mOverrideDisplayInfo.overscanLeft = left;
+ mOverrideDisplayInfo.overscanTop = top;
+ mOverrideDisplayInfo.overscanRight = right;
+ mOverrideDisplayInfo.overscanBottom = bottom;
+ }
+ }
+
/**
* Returns true if the logical display is in a valid state.
* This method should be checked after calling {@link #updateLocked} to handle the
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 89e0f17..938fa5c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -19,6 +19,9 @@
import static com.android.server.wm.WindowManagerService.FORWARD_ITERATOR;
import static com.android.server.wm.WindowManagerService.REVERSE_ITERATOR;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -225,6 +228,10 @@
public void remove() {
throw new IllegalArgumentException();
}
+
+ @Override public String toString() {
+ return mTaskLists.toString();
+ }
}
class AppTokenIterator implements Iterator<AppWindowToken> {
@@ -291,6 +298,10 @@
}
return size;
}
+
+ @Override public String toString() {
+ return mIterator.toString();
+ }
}
public void dump(String prefix, PrintWriter pw) {
@@ -316,6 +327,7 @@
pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+ pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
AppTokenIterator iterator = getTmpAppIterator(REVERSE_ITERATOR);
int ndx = iterator.size() - 1;
if (ndx >= 0) {
@@ -360,7 +372,6 @@
pw.println();
}
}
- pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
pw.println();
}
}
diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/java/com/android/server/wm/DisplaySettings.java
new file mode 100644
index 0000000..34d1a64
--- /dev/null
+++ b/services/java/com/android/server/wm/DisplaySettings.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 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.server.wm;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Current persistent settings about a display
+ */
+public class DisplaySettings {
+ private static final String TAG = WindowManagerService.TAG;
+
+ private final Context mContext;
+ private final AtomicFile mFile;
+ private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
+
+ public static class Entry {
+ public final String name;
+ public int overscanLeft;
+ public int overscanTop;
+ public int overscanRight;
+ public int overscanBottom;
+
+ public Entry(String _name) {
+ name = _name;
+ }
+ }
+
+ public DisplaySettings(Context context) {
+ mContext = context;
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ mFile = new AtomicFile(new File(systemDir, "display_settings.xml"));
+ }
+
+ public void getOverscanLocked(String name, Rect outRect) {
+ Entry entry = mEntries.get(name);
+ if (entry != null) {
+ outRect.left = entry.overscanLeft;
+ outRect.top = entry.overscanTop;
+ outRect.right = entry.overscanRight;
+ outRect.bottom = entry.overscanBottom;
+ } else {
+ outRect.set(0, 0, 0, 0);
+ }
+ }
+
+ public void setOverscanLocked(String name, int left, int top, int right, int bottom) {
+ if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+ // Right now all we are storing is overscan; if there is no overscan,
+ // we have no need for the entry.
+ mEntries.remove(name);
+ return;
+ }
+ Entry entry = mEntries.get(name);
+ if (entry == null) {
+ entry = new Entry(name);
+ mEntries.put(name, entry);
+ }
+ entry.overscanLeft = left;
+ entry.overscanTop = top;
+ entry.overscanRight = right;
+ entry.overscanBottom = bottom;
+ }
+
+ public void readSettingsLocked() {
+ FileInputStream stream;
+ try {
+ stream = mFile.openRead();
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "No existing display settings " + mFile.getBaseFile()
+ + "; starting empty");
+ return;
+ }
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ readDisplay(parser);
+ } else {
+ Slog.w(TAG, "Unknown element under <display-settings>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ if (!success) {
+ mEntries.clear();
+ }
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ private int getIntAttribute(XmlPullParser parser, String name) {
+ try {
+ String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.parseInt(str) : 0;
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
+ private void readDisplay(XmlPullParser parser) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ Entry entry = new Entry(name);
+ entry.overscanLeft = getIntAttribute(parser, "overscanLeft");
+ entry.overscanTop = getIntAttribute(parser, "overscanTop");
+ entry.overscanRight = getIntAttribute(parser, "overscanRight");
+ entry.overscanBottom = getIntAttribute(parser, "overscanBottom");
+ mEntries.put(name, entry);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ public void writeSettingsLocked() {
+ FileOutputStream stream;
+ try {
+ stream = mFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, "display-settings");
+
+ for (Entry entry : mEntries.values()) {
+ out.startTag(null, "display");
+ out.attribute(null, "name", entry.name);
+ if (entry.overscanLeft != 0) {
+ out.attribute(null, "overscanLeft", Integer.toString(entry.overscanLeft));
+ }
+ if (entry.overscanTop != 0) {
+ out.attribute(null, "overscanTop", Integer.toString(entry.overscanTop));
+ }
+ if (entry.overscanRight != 0) {
+ out.attribute(null, "overscanRight", Integer.toString(entry.overscanRight));
+ }
+ if (entry.overscanBottom != 0) {
+ out.attribute(null, "overscanBottom", Integer.toString(entry.overscanBottom));
+ }
+ out.endTag(null, "display");
+ }
+
+ out.endTag(null, "display-settings");
+ out.endDocument();
+ mFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings, restoring backup.", e);
+ mFile.failWrite(stream);
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
index 5e82af2..1f1dd58 100644
--- a/services/java/com/android/server/wm/TaskGroup.java
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -23,4 +23,9 @@
public class TaskGroup {
public int taskId = -1;
public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
+
+ @Override
+ public String toString() {
+ return "id=" + taskId + " tokens=" + tokens;
+ }
}
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
index 88791f2..67dfa4f 100644
--- a/services/java/com/android/server/wm/TaskList.java
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -27,4 +27,9 @@
mAppTokens.add(wtoken);
mDisplayContent = displayContent;
}
+
+ @Override
+ public String toString() {
+ return "id=" + taskId + " appTokens=" + mAppTokens;
+ }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index d38273d..b193430 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -320,6 +320,8 @@
final AppOpsManager mAppOps;
+ final DisplaySettings mDisplaySettings;
+
/**
* All currently active sessions with clients.
*/
@@ -731,6 +733,8 @@
com.android.internal.R.bool.config_sf_limitedAlpha);
mDisplayManagerService = displayManager;
mHeadless = displayManager.isHeadless();
+ mDisplaySettings = new DisplaySettings(context);
+ mDisplaySettings.readSettingsLocked();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this, null);
@@ -3120,8 +3124,9 @@
return;
}
+ boolean mismatch = false;
AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
- for ( ; t >= 0; --t) {
+ for ( ; t >= 0 && !mismatch; --t) {
task = tasks.get(t);
List<IApplicationToken> tokens = task.tokens;
int v = task.tokens.size() - 1;
@@ -3133,28 +3138,22 @@
return;
}
- while (v >= 0 && iterator.hasNext()) {
+ while (v >= 0) {
AppWindowToken atoken = iterator.next();
if (atoken.removed) {
continue;
}
if (tokens.get(v) != atoken.token) {
- Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
- + " @ " + v + ", internal is " + atoken.token);
+ mismatch = true;
+ break;
}
v--;
}
- while (v >= 0) {
- Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
- v--;
- }
}
- while (iterator.hasNext()) {
- AppWindowToken atoken = iterator.next();
- if (!atoken.removed) {
- Slog.w(TAG, "Invalid internal atoken: " + atoken.token);
- }
+ if (mismatch || iterator.hasNext()) {
+ Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks
+ + " WindowManager=" + iterator);
}
}
}
@@ -5313,8 +5312,14 @@
if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
- rotation == -1 ? mRotation : rotation);
+ long origId = Binder.clearCallingIdentity();
+ try {
+ mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
+ rotation == -1 ? mRotation : rotation);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
updateRotationUnchecked(false, false);
}
@@ -5331,7 +5336,14 @@
if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
- mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
+ long origId = Binder.clearCallingIdentity();
+ try {
+ mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
+ 777); // rot not used
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
updateRotationUnchecked(false, false);
}
@@ -7089,6 +7101,15 @@
@Override
public void setForcedDisplaySize(int displayId, int width, int height) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
synchronized(mWindowMap) {
// Set some sort of reasonable bounds on the size of the display that we
// will try to emulate.
@@ -7160,6 +7181,15 @@
@Override
public void clearForcedDisplaySize(int displayId) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
@@ -7173,6 +7203,15 @@
@Override
public void setForcedDisplayDensity(int displayId, int density) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
@@ -7195,6 +7234,15 @@
@Override
public void clearForcedDisplayDensity(int displayId) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("Can only set the default display");
+ }
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
@@ -7233,6 +7281,33 @@
performLayoutAndPlaceSurfacesLocked();
}
+ public void setOverscan(int displayId, int left, int top, int right, int bottom) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold permission " +
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ synchronized(mWindowMap) {
+ DisplayContent displayContent = getDisplayContentLocked(displayId);
+ if (displayContent != null) {
+ mDisplayManagerService.setOverscan(displayId, left, top, right, bottom);
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ synchronized(displayContent.mDisplaySizeLock) {
+ displayInfo.overscanLeft = left;
+ displayInfo.overscanTop = top;
+ displayInfo.overscanRight = right;
+ displayInfo.overscanBottom = bottom;
+ }
+ mPolicy.setDisplayOverscan(displayContent.getDisplay(), left, top, right, bottom);
+ displayContent.layoutNeeded = true;
+ mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
+ mDisplaySettings.writeSettingsLocked();
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ }
+
@Override
public boolean hasSystemNavBar() {
return mPolicy.hasSystemNavBar();
@@ -9694,7 +9769,7 @@
if (dumpAll) {
pw.print(" mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
- pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
+ pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
if (mLastStatusBarVisibility != 0) {
pw.print(" mLastStatusBarVisibility=0x");
pw.println(Integer.toHexString(mLastStatusBarVisibility));
@@ -9973,12 +10048,28 @@
}
}
+ private DisplayContent newDisplayContentLocked(final Display display) {
+ DisplayContent displayContent = new DisplayContent(display);
+ mDisplayContents.put(display.getDisplayId(), displayContent);
+ final Rect rect = new Rect();
+ DisplayInfo info = displayContent.getDisplayInfo();
+ mDisplaySettings.getOverscanLocked(info.name, rect);
+ info.overscanLeft = rect.left;
+ info.overscanTop = rect.top;
+ info.overscanRight = rect.right;
+ info.overscanBottom = rect.bottom;
+ mDisplayManagerService.setOverscan(display.getDisplayId(), rect.left, rect.top,
+ rect.right, rect.bottom);
+ mPolicy.setDisplayOverscan(displayContent.getDisplay(), rect.left, rect.top,
+ rect.right, rect.bottom);
+ return displayContent;
+ }
+
public void createDisplayContentLocked(final Display display) {
if (display == null) {
throw new IllegalArgumentException("getDisplayContent: display must not be null");
}
- final DisplayContent displayContent = new DisplayContent(display);
- mDisplayContents.put(display.getDisplayId(), displayContent);
+ newDisplayContentLocked(display);
}
/**
@@ -9992,8 +10083,7 @@
if (displayContent == null) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display != null) {
- displayContent = new DisplayContent(display);
- mDisplayContents.put(displayId, displayContent);
+ displayContent = newDisplayContentLocked(display);
}
}
return displayContent;
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 81a2c14..4ff3899 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,7 +10,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
easymocklib \
guava \
- littlemock
+ mockito-target
LOCAL_JAVA_LIBRARIES := android.test.runner services
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index f14569c..ffd1568 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
+import android.os.UserHandle;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AbstractFuture;
@@ -133,12 +134,28 @@
}
@Override
+ public void sendBroadcast(Intent intent, String receiverPermission) {
+ sendBroadcast(intent);
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+ sendBroadcast(intent);
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendStickyBroadcast(Intent intent) {
sendBroadcast(intent);
}
@Override
- public void sendBroadcast(Intent intent, String receiverPermission) {
+ public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 93ea6a2..4ae013b 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -21,16 +21,15 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
-import static com.google.testing.littlemock.LittleMock.anyInt;
-import static com.google.testing.littlemock.LittleMock.createCaptor;
-import static com.google.testing.littlemock.LittleMock.doNothing;
-import static com.google.testing.littlemock.LittleMock.doReturn;
-import static com.google.testing.littlemock.LittleMock.doThrow;
-import static com.google.testing.littlemock.LittleMock.eq;
-import static com.google.testing.littlemock.LittleMock.isA;
-import static com.google.testing.littlemock.LittleMock.mock;
-import static com.google.testing.littlemock.LittleMock.reset;
-import static com.google.testing.littlemock.LittleMock.verify;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.INetworkPolicyManager;
@@ -48,7 +47,7 @@
import android.util.Log;
import android.util.LogPrinter;
-import com.google.testing.littlemock.ArgumentCaptor;
+import org.mockito.ArgumentCaptor;
import java.net.InetAddress;
import java.util.concurrent.Future;
@@ -128,7 +127,7 @@
doReturn(mWifi.tracker)
.when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class));
- final ArgumentCaptor<Handler> trackerHandler = createCaptor();
+ final ArgumentCaptor<Handler> trackerHandler = ArgumentCaptor.forClass(Handler.class);
doNothing().when(mMobile.tracker)
.startMonitoring(isA(Context.class), trackerHandler.capture());
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index ed44b04..278413e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -110,6 +110,12 @@
}
@Override
+ public void setOverscan(int displayId, int left, int top, int right, int bottom)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void closeSystemDialogs(String arg0) throws RemoteException {
// TODO Auto-generated method stub