diff options
20 files changed, 727 insertions, 141 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 19b1cf3c86ba..48bdcb2e6720 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1814,6 +1814,19 @@ public final class ViewRootImpl implements ViewParent, + mAttachInfo.mVisibleInsets); } + // If any of the insets changed, do a forceLayout on the view so that the + // measure cache is cleared. We might have a pending MSG_RESIZED_REPORT + // that is supposed to take care of it, but since pending insets are + // already modified here, it won't detect the frame change after this. + final boolean framesChanged = overscanInsetsChanged + || contentInsetsChanged + || stableInsetsChanged + || visibleInsetsChanged + || outsetsChanged; + if (mAdded && mView != null && framesChanged) { + forceLayout(mView); + } + if (!hadSurface) { if (mSurface.isValid()) { // If we are creating a new surface, then we need to diff --git a/core/res/res/layout/unsupported_display_size_dialog_content.xml b/core/res/res/layout/unsupported_display_size_dialog_content.xml new file mode 100644 index 000000000000..5e5cf00b27ac --- /dev/null +++ b/core/res/res/layout/unsupported_display_size_dialog_content.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2016 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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="?attr/dialogPreferredPadding" + android:paddingLeft="?attr/dialogPreferredPadding" + android:paddingRight="?attr/dialogPreferredPadding"> + + <CheckBox + android:id="@+id/ask_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:text="@string/unsupported_display_size_show" /> +</FrameLayout> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 48744b61b965..b55a9b22118b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2768,6 +2768,11 @@ <!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. --> <string name="screen_compat_mode_hint">Re-enable this in System settings > Apps > Downloaded.</string> + <!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. --> + <string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string> + <!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. --> + <string name="unsupported_display_size_show">Always show</string> + <!-- Text of the alert that is displayed when an application has violated StrictMode. --> <string name="smv_application">The app <xliff:g id="application">%1$s</xliff:g> (process <xliff:g id="process">%2$s</xliff:g>) has violated its self-enforced StrictMode policy.</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7e9b57c7a49b..d154b034e058 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2609,4 +2609,7 @@ <java-symbol type="array" name="config_defaultPinnerServiceFiles" /> <java-symbol type="string" name="suspended_widget_accessibility" /> + + <java-symbol type="layout" name="unsupported_display_size_dialog_content" /> + <java-symbol type="string" name="unsupported_display_size_message" /> </resources> diff --git a/docs/html/ndk/downloads/index.jd b/docs/html/ndk/downloads/index.jd index 47d3113b8921..954b049798c8 100644 --- a/docs/html/ndk/downloads/index.jd +++ b/docs/html/ndk/downloads/index.jd @@ -332,35 +332,199 @@ $('#Downloads').after($('#download-table')); <h2 id="rel">Release Notes</h2> <p> - Android NDK, Revision 11c <em>(March 2016)</em> + Android NDK, Revision 12 <em>(June 2016)</em> </p> <dl> - <dt> - NDK - </dt> - - <dd> - <ul> - <li>Changes - <ul> - <li>Applied additional fixes to the {@code ndk-gdb.py} script. - </li> - <li>Added an optional package name argument to the {@code ndk-gdb} - command {@code --attach} option. - (<a href="https://github.com/android-ndk/ndk/issues/13">Issue 13</a>) - </li> - <li>Fixed invalid toolchain paths for 32-bit Windows platform. - (<a href="https://github.com/android-ndk/ndk/issues/45">Issue 45</a>) - </li> - <li>Fixed the relative path for the {@code ndk-which} command. - (<a href="https://github.com/android-ndk/ndk/issues/29">Issue 29</a>) - </li> - <li>Fixed use of cygpath for the libgcc compiler. - (Android <a href="http://b.android.com/195486">Issue 195486</a>) - </li> - </ul> - </li> - </ul> - </dd> -</dl>
\ No newline at end of file +<dt> + Announcements +</dt> + +<ul> + <li>The <code>ndk-build</code> command will default to using + Clang in an upcoming release. GCC will be removed in a later release. + </li> + <li>The <code>make-standalone-toolchain.sh</code> script will be removed + in an upcoming release. If you use this script, please plan to migrate to the + <code>make_standalone_toolchain.py</code> as soon as possible. + </li> +</ul> + +<dt> + NDK +</dt> + +<ul> + <li>Removed support for the armeabi-v7a-hard ABI. See the explanation in the + <a href= + "https://android.googlesource.com/platform/ndk/+/ndk-r12-release/docs/HardFloatAbi.md"> + documentation</a>. + </li> + + <li>Removed all sysroots for platform levels prior to Android 2.3 (API level 10). + We dropped support for them in NDK r11, but neglected to actually remove them. + </li> + + <li>Updated exception handling when using c++_shared on ARM32 so that it + mostly works (see <a href="#known-issues">Known Issues</a>). The unwinder + is now linked into each linked object rather than into libc++ itself. + </li> + + <li>Pruned the default compiler flags (<a href= + "https://github.com/android-ndk/ndk/issues/27">NDK Issue 27</a>). You can see + details of this update in <a href= + "https://android-review.googlesource.com/#/c/207721/5">Change 207721</a>. + </li> + + <li>Added a Python implementation of standalone toolchains in <code> + build/tools/make_standalone_toolchain.py</code>. On Windows, you no longer + need Cygwin to use this feature. Note that the bash flavor will be removed + in an upcoming release, so please test the new one now. + </li> + + <li>Configured Clang debug builds to have the <code>-fno-limit-debug-info</code> + option is enabled by default. This change enables better debugging with LLDB. + </li> + + <li>Enabled the <code>--build-id</code> as a default option. This option + causes an identifier to be shown in native crash reports so you can easily + identify which version of your code was running. + </li> + + <li>Fixed issue with <code>NDK_USE_CYGPATH</code> so that it no longer causes + problems with libgcc + (<a href="http://b.android.com/195486">Issue 195486</a>). + </li> + + <li>Enabled the following options as default: + <code>-Wl,--warn-shared-textrel</code> and <code>-Wl,--fatal-warnings</code>. + If you have shared text relocations, your app does not load on Android 6.0 + (API level 23) and higher. Note that this configuration has never been + allowed for 64-bit apps. + </li> + + <li>Fixed a few issues so that precompiled headers work better + (<a href="https://github.com/android-ndk/ndk/issues/14">NDK Issue 14</a>, + <a href="https://github.com/android-ndk/ndk/issues/16">NDK Issue 16</a>). + </li> + + <li>Removed unreachable ARM (non-thumb) STL libraries. + </li> + + <li>Added Vulkan support to android-24. + </li> + + <li>Added Choreographer API to android-24. + </li> + + <li>Added libcamera2 APIs for devices that support the + <code>INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED</code> feature level or higher. + For more information, see the + <a href="{@docRoot}reference/android/hardware/camera2/CameraCharacteristics.html#INFO_SUPPORTED_HARDWARE_LEVEL"> + <code>CameraCharacteristics</code></a> reference. + </li> + +</ul> + +<dt> + Clang +</dt> + +<ul> + <li>Clang has been updated to 3.8svn (r256229, build 2812033). Note that + Clang packaged in the Windows 64-bit NDK is actually 32-bit. + </li> + + <li>Fixed <code>__thread</code> so that it works for real this time. + </li> +</ul> + +<dt> + GCC +</dt> + +<ul> + <li>Synchronized the compiler with the ChromeOS GCC @ google/gcc-4_9 r227810. + </li> + + <li>Backported coverage sanitizer patch from ToT (r231296). + </li> + + <li>Fixed <code>libatomic</code> to not use ifuncs (<a href= + "https://github.com/android-ndk/ndk/issues/31">NDK Issue 31</a>). + </li> +</ul> + +<dt> + Binutils +</dt> + +<ul> + <li>Silenced the "Erratum 843419 found and fixed" info messages. + </li> + + <li>Introduced option <code>--long-plt</code> to fix an internal linker error + when linking huge arm32 binaries. + </li> + + <li>Fixed wrong run time stubs for <code>AArch64</code>. This problem was + causing jump addresses to be calculated incorrectly for very large + dynamic shared objects (DSOs). + </li> + + <li>Introduced default option <code>--no-apply-dynamic</code> to work around + a dynamic linker bug for earlier Android releases. + </li> + + <li>Fixed a known issue with NDK r11 where <code>dynamic_cast</code> was not + working with Clang, x86, stlport_static and optimization. + </li> +</ul> + +<dt> + GDB +</dt> + +<ul> + <li>Updated to GDB version 7.11. For more information about this release, see + <a href="https://www.gnu.org/software/gdb/news/">GDB News</a>. + </li> + + <li>Fixed a number of bugs in the <code>ndk-gdb.py</code> script. + </li> +</ul> + +<dt id="known-issues"> + Known Issues +</dt> + +<ul> + <li>The x86 <a href="http://source.android.com/devices/tech/debug/asan.html">Address + Sanitizer</a> (ASAN) currently does not work. For more information, see + <a href="https://android-review.googlesource.com/#/c/186276/">Issue 186276</a>. + </li> + + <li>Exception unwinding with <code>c++_shared</code> does not work for ARM on + Android 2.3 (API level 9) or Android 4.0 (API level 14). + </li> + + <li>Bionic headers and libraries for Android 6.0 (API level 23) and higher + are not yet exposed despite the presence of android-24. Those platforms still + have the Android 5.0 (API level 21) headers and libraries, which is consistent + with NDK r11. + </li> + + <li>The RenderScript tools are not present, which is consistent with + NDK r11. + (<a href="https://github.com/android-ndk/ndk/issues/7">NDK Issue 7</a>) + </li> + + <li>In <code>NdkCameraMetadataTags.h</code> header file, the camera metadata + tag enum value <code>ACAMERA_STATISTICS_LENS_SHADING_CORRECTION_MAP</code> + was listed by accident and will be removed in next release. Use + the <code>ACAMERA_STATISTICS_LENS_SHADING_MAP</code> value instead. + </li> + +</ul> + +</dl> diff --git a/docs/html/ndk/downloads/revision_history.jd b/docs/html/ndk/downloads/revision_history.jd index c5a0d4895489..211b64e5be4b 100644 --- a/docs/html/ndk/downloads/revision_history.jd +++ b/docs/html/ndk/downloads/revision_history.jd @@ -10,6 +10,44 @@ took place in each new version.</p> <p> <a href="#" onclick="return toggleContent(this)"> <img src="/assets/images/styles/disclosure_down.png" class="toggle-content-img" alt="" + >Android NDK, Revision 11c</a> <em>(March 2016)</em> + </p> + <div class="toggle-content-toggleme"> + +<dl> + <dd> + <ul> + <li>Changes + <ul> + <li>Applied additional fixes to the {@code ndk-gdb.py} script. + </li> + <li>Added an optional package name argument to the {@code ndk-gdb} + command {@code --attach} option. + (<a href="https://github.com/android-ndk/ndk/issues/13">Issue 13</a>) + </li> + <li>Fixed invalid toolchain paths for 32-bit Windows platform. + (<a href="https://github.com/android-ndk/ndk/issues/45">Issue 45</a>) + </li> + <li>Fixed the relative path for the {@code ndk-which} command. + (<a href="https://github.com/android-ndk/ndk/issues/29">Issue 29</a>) + </li> + <li>Fixed use of cygpath for the libgcc compiler. + (Android <a href="http://b.android.com/195486">Issue 195486</a>) + </li> + </ul> + </li> + </ul> + </dd> +</dl> + + </div> +</div> + +<div class="toggle-content closed"> +<a name="11b"></a> + <p> + <a href="#" onclick="return toggleContent(this)"> <img + src="/assets/images/styles/disclosure_down.png" class="toggle-content-img" alt="" >Android NDK, Revision 11b</a> <em>(March 2016)</em> </p> <div class="toggle-content-toggleme"> diff --git a/docs/html/sdk/sdk_vars.cs b/docs/html/sdk/sdk_vars.cs index 32fdb0aec360..80da297c9bf7 100644 --- a/docs/html/sdk/sdk_vars.cs +++ b/docs/html/sdk/sdk_vars.cs @@ -1,18 +1,19 @@ <?cs -set:ndk.mac64_download='android-ndk-r11c-darwin-x86_64.zip' ?><?cs -set:ndk.mac64_bytes='772428792' ?><?cs -set:ndk.mac64_checksum='4ce8e7ed8dfe08c5fe58aedf7f46be2a97564696' ?><?cs +set:ndk.mac64_download='android-ndk-r12-darwin-x86_64.zip' ?><?cs +set:ndk.mac64_bytes='734014148' ?><?cs +set:ndk.mac64_checksum='708d4025142924f7097a9f44edf0a35965706737' ?><?cs -set:ndk.linux64_download='android-ndk-r11c-linux-x86_64.zip' ?><?cs -set:ndk.linux64_bytes='794135138' ?><?cs -set:ndk.linux64_checksum='de5ce9bddeee16fb6af2b9117e9566352aa7e279' ?><?cs +set:ndk.linux64_download='android-ndk-r12-linux-x86_64.zip' ?><?cs +set:ndk.linux64_bytes='755431993' ?><?cs +set:ndk.linux64_checksum='b7e02dc733692447366a2002ad17e87714528b39' ?><?cs -set:ndk.win64_download='android-ndk-r11c-windows-x86_64.zip' ?><?cs -set:ndk.win64_bytes='771407642' ?><?cs -set:ndk.win64_checksum='3d89deb97b3191c7e5555f1313ad35059479f071' ?><?cs -set:ndk.win32_download='android-ndk-r11c-windows-x86.zip' ?><?cs -set:ndk.win32_bytes='728899082' ?><?cs -set:ndk.win32_checksum='ff939bde6cd374eecbd2c3b2ad218697f9a5038c' +set:ndk.win64_download='android-ndk-r12-windows-x86.zip' ?><?cs +set:ndk.win64_bytes='706332762' ?><?cs +set:ndk.win64_checksum='37fcd7acf6012d0068a57c1524edf24b0fef69c9' ?><?cs + +set:ndk.win32_download='android-ndk-r12-windows-x86_64.zip' ?><?cs +set:ndk.win32_bytes='749444245' ?><?cs +set:ndk.win32_checksum='80d64a77aab52df867ac55cec1e976663dd3326f' ?> <?cs def:size_in_mb(bytes) diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd index ca8784ebfcfb..293de51ea000 100644 --- a/docs/html/topic/libraries/data-binding/index.jd +++ b/docs/html/topic/libraries/data-binding/index.jd @@ -18,7 +18,7 @@ page.tags="databinding", "layouts" <a href="#data_binding_layout_files">Data Binding Layout Files</a> <ol> <li> - <a href="#writing_expressions">Writing your first data binding + <a href="#writing_expressions">Writing your first set of data binding expressions</a> </li> @@ -29,9 +29,16 @@ page.tags="databinding", "layouts" <li> <a href="#binding_data">Binding Data</a> </li> - <li> - <a href="#binding_events">Binding Events</a> + <a href="#event_handling">Event Handling</a> + <ol> + <li> + <a href="#method_references">Method References</a> + </li> + <li> + <a href="#listener_bindings">Listener Bindings</a> + </li> + </ol> </li> </ol> </li> @@ -147,27 +154,34 @@ page.tags="databinding", "layouts" application logic and layouts. </p> -<p>The Data Binding Library offers both flexibility and broad compatibility -— it's a support library, so you can use it with all Android platform -versions back to <strong>Android 2.1</strong> (API level 7+).</p> +<p> + The Data Binding Library offers both flexibility and broad compatibility — + it's a support library, so you can use it with all Android platform versions + back to <strong>Android 2.1</strong> (API level 7+). +</p> -<p>To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong> -or higher is required.</p> +<p> + To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong> + or higher is required. +</p> <h2 id="build_environment"> Build Environment </h2> -<p>To get started with Data Binding, download the library from the Support -repository in the Android SDK manager. </p> - <p> -To configure your app to use data binding, add the <code>dataBinding</code> element to your -<code>build.gradle</code> file in the app module. + To get started with Data Binding, download the library from the Support + repository in the Android SDK manager. </p> - <p>Use the following code snippet to configure data binding: </p> +<p> + To configure your app to use data binding, add the <code>dataBinding</code> + element to your <code>build.gradle</code> file in the app module. +</p> +<p> + Use the following code snippet to configure data binding: +</p> <pre> android { .... @@ -176,13 +190,17 @@ android { } } </pre> +<p> + If you have an app module that depends on a library which uses data binding, + your app module must configure data binding in its <code>build.gradle</code> + file as well. +</p> -<p>If you have an app module that depends on a library which uses data binding, your app module - must configure data binding in its <code>build.gradle</code> file as well.</p> - -<p>Also, make sure you are using a compatible version of Android Studio. -<strong>Android Studio 1.3</strong> and later provides support for data binding as described in -<a href="#studio_support">Android Studio Support for Data Binding</a>. +<p> + Also, make sure you are using a compatible version of Android Studio. + <strong>Android Studio 1.3</strong> and later provides support for data + binding as described in <a href="#studio_support">Android Studio Support for + Data Binding</a>. </p> <h2 id="data_binding_layout_files"> @@ -190,7 +208,7 @@ android { </h2> <h3 id="writing_expressions"> - Writing your first data binding expressions + Writing your first set of data binding expressions </h3> <p> @@ -223,20 +241,19 @@ android { The user <strong>variable</strong> within <strong>data</strong> describes a property that may be used within this layout. </p> - <pre> <<strong>variable name="user" type="com.example.User"</strong>/> </pre> <p> Expressions within the layout are written in the attribute properties using - the “<code>@{}</code>” syntax. Here, the TextView’s text is set to the - firstName property of user: + the “<code>&commat;{}</code>” syntax. Here, the TextView’s text is set to + the firstName property of user: </p> <pre> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@{user.firstName}"/> + android:text="&commat;{user.firstName}"/> </pre> <h3 id="data_object"> Data Object @@ -261,7 +278,6 @@ public class User { to have data that is read once and never changes thereafter. It is also possible to use a JavaBeans objects: </p> - <pre> public class User { private final String firstName; @@ -280,11 +296,12 @@ public class User { </pre> <p> From the perspective of data binding, these two classes are equivalent. The - expression <strong><code>@{user.firstName}</code></strong> used for - the TextView’s <strong><code>android:text</code></strong> attribute will + expression <strong><code>&commat;{user.firstName}</code></strong> used + for the TextView’s <strong><code>android:text</code></strong> attribute will access the <strong><code>firstName</code></strong> field in the former class - and the <code>getFirstName()</code> method in the latter class. Alternatively, it - will also be resolved to <code>firstName()</code> if that method exists. + and the <code>getFirstName()</code> method in the latter class. + Alternatively, it will also be resolved to <code>firstName()</code> if that + method exists. </p> <h3 id="binding_data"> @@ -328,16 +345,38 @@ ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, fal //or ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.layout.<em><strong>list_item</strong></em>, viewGroup, <strong>false</strong>); </pre> - -<h3 id="binding_events"> - Binding Events -</h3> +<h3 id="event_handling">Event Handling</h3> <p> - Events may be bound to handler methods directly, similar to the way - <strong><code>android:onClick</code></strong> can be assigned to a method in the Activity. - Event attribute names are governed by the name of the listener method with a few exceptions. - For example, {@link android.view.View.OnLongClickListener} has a method {@link android.view.View.OnLongClickListener#onLongClick onLongClick()}, - so the attribute for this event is <code>android:onLongClick</code>. +Data Binding allows you to write expressions handling events that are dispatched from the views (e.g. onClick). +Event attribute names are governed by the name of the listener method with a few exceptions. +For example, {@link android.view.View.OnLongClickListener} has a method {@link android.view.View.OnLongClickListener#onLongClick onLongClick()}, +so the attribute for this event is <code>android:onLongClick</code>. +There are two ways to handle an event. +</p> +<ul> + <li> + <a href="#method_references">Method References</a>: In your expressions, you can reference methods that conform to the signature of the listener method. When an expression evaluates to a method reference, Data Binding wraps the method reference and owner object in a listener, and sets that listener on the target view. If the expression evaluates to null, Data Binding does not create a listener and sets a null listener instead. + </li> + <li> + <a href="#listener_bindings">Listener Bindings</a>: These are lambda expressions that are evaluated when the event happens. +Data Binding always creates a listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression. + </li> +</ul> +<h4 id="method_references"> + Method References +</h4> +<p> + Events can be bound to handler methods directly, similar to the way + <strong><code>android:onClick</code></strong> can be assigned to a method in an Activity. + One major advantage compared to the {@code View#onClick} attribute is that the expression + is processed at compile time, so if the method does not exist or its signature is not + correct, you receive a compile time error.</p> +<p> + The major difference between Method References and Listener Bindings is that + the actual listener implementation is created when the data is bound, not + when the event is triggered. If you prefer to evaluate the expression when + the event happens, you should use <a href="#listener_bindings">listener + binding</a>. </p> <p> To assign an event to its handler, use a normal binding expression, with the value @@ -345,7 +384,6 @@ ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.lay </p> <pre>public class MyHandlers { public void onClickFriend(View view) { ... } - public void onClickEnemy(View view) { ... } } </pre> <p> @@ -365,14 +403,121 @@ ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.lay <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" - android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> - <TextView android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@{user.lastName}" - android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/> + android:onClick="@{handlers::onClickFriend}"/> </LinearLayout> </layout> </pre> +<p> +Note that the signature of the method in the expression must exactly match the signature of the method in the +Listener object. +</p> +<h4 id="listener_bindings"> + Listener Bindings +</h4> +<p> + Listener Bindings are binding expressions that run when an event happens. + They are similar to method references, but they let you run arbitrary data + binding expressions. This feature is available with Android Gradle Plugin for Gradle + version 2.0 and later. +</p> +<p> + In method references, the parameters of the method must + match the parameters of the event listener. In Listener Bindings, only your + return value must match the expected return value of the listener (unless it + is expecting void). + For example, you can have a presenter class that has the following method: +</p> +<pre> +public class Presenter { + public void onSaveClick(Task task){} +} +</pre> + Then you can bind the click event to your class as follows: +<pre> + <?xml version="1.0" encoding="utf-8"?> + <layout xmlns:android="http://schemas.android.com/apk/res/android"> + <data> + <variable name="task" type="com.android.example.Task" /> + <variable name="presenter" type="com.android.example.Presenter" /> + </data> + <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> + <Button android:layout_width="wrap_content" android:layout_height="wrap_content" + android:onClick="@{() -> presenter.onSaveClick(task)}" /> + </LinearLayout> + </layout> +</pre> +<p> + Listeners are represented by lambda expressions that are allowed only as root + elements of your expressions. When a callback is used in an expression, Data + Binding automatically creates the necessary listener and registers for the + event. When the view fires the event, Data Binding evaluates the given + expression. As in regular binding expressions, you still get the null and + thread safety of Data Binding while these listener expressions are being + evaluated. +</p> +<p> + Note that in the example above, we haven't defined the {@code view} parameter + that is passed into {@link + android.view.View.OnClickListener#onClick(android.view.View view)}. Listener + bindings provide two choices for listener parameters: you can either ignore + all parameters to the method or name all of them. If you prefer to name the + parameters, you can use them in your expression. For example, the expression + above could be written as: +</p> +<pre> + android:onClick="@{(view) -> presenter.onSaveClick(task)}" +</pre> +Or if you wanted to use the parameter in the expression, it could work as follows: +<pre> +public class Presenter { + public void onSaveClick(View view, Task task){} +} +</pre> +<pre> + android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}" +</pre> +You can use a lambda expression with more than one parameter: +<pre> +public class Presenter { + public void onCompletedChanged(Task task, boolean completed){} +} +</pre> +<pre> + <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" + android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" /> +</pre> +<p> + If the event you are listening to returns a value whose type is not {@code + void}, your expressions must return the same type of value as well. For + example, if you want to listen for the long click event, your expression + should return {@code boolean}. +</p> +<pre> +public class Presenter { + public boolean onLongClick(View view, Task task){} +} +</pre> +<pre> + android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}" +</pre> +<p> +If the expression cannot be evaluated due to {@code null} objects, Data Binding returns +the default Java value for that type. For example, {@code null} for reference types, {@code 0} for {@code int}, +{@code false} for {@code boolean}, etc. +</p> +<p> +If you need to use an expression with a predicate (e.g. ternary), you can use +{@code void} as a symbol. +</p> +<pre> + android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}" +</pre> + +<h5>Avoid Complex Listeners</h5> +Listener expressions are very powerful and can make your code very easy to read. +On the other hand, listeners containing complex expressions make your layouts hard to read and unmaintainable. +These expressions should be as simple as passing available data from your UI to your callback method. You should implement +any business logic inside the callback method that you invoked from the listener expression. <p> Some specialized click event handlers exist and they need an attribute other than diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index c984abe1b8e0..f287f1bac6cb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -113,6 +113,11 @@ public class QuickQSPanel extends QSPanel { } @Override + protected void onTileClick(QSTile<?> tile) { + tile.secondaryClick(); + } + + @Override public void onTuningChanged(String key, String newValue) { // No tunings for you. if (key.equals(QS_SHOW_BRIGHTNESS)) { @@ -130,7 +135,7 @@ public class QuickQSPanel extends QSPanel { break; } } - super.setTiles(quickTiles, false); + super.setTiles(quickTiles, true); } private final Tunable mNumTiles = new Tunable() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index 18191cf782dc..0de5105485dc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -95,14 +95,6 @@ public class CellularTile extends QSTile<QSTile.SignalState> { } @Override - protected void handleSecondaryClick() { - boolean dataEnabled = mDataController.isMobileDataSupported() - && mDataController.isMobileDataEnabled(); - MetricsLogger.action(mContext, MetricsEvent.QS_CELLULAR_TOGGLE, !dataEnabled); - mDataController.setMobileDataEnabled(!dataEnabled); - } - - @Override public CharSequence getTileLabel() { return mContext.getString(R.string.quick_settings_cellular_detail_title); } @@ -152,8 +144,8 @@ public class CellularTile extends QSTile<QSTile.SignalState> { } state.contentDescription = state.contentDescription + "," + r.getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); - state.expandedAccessibilityClassName = Button.class.getName(); - state.minimalAccessibilityClassName = Switch.class.getName(); + state.minimalAccessibilityClassName = state.expandedAccessibilityClassName + = Button.class.getName(); state.value = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 43f847c23f81..71ef1eacfa6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -1961,8 +1961,7 @@ public class NotificationStackScrollLayout extends ViewGroup // we're ending up at the same location as we are now, lets just skip the animation bottom = finalBottom; } else { - bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight() - - lastView.getExtraBottomPadding()); + bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()); bottom = Math.min(bottom, getHeight()); } } else { diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 4e0ddd6a75cb..2a3022962d45 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -20,6 +20,7 @@ import static android.content.Context.KEYGUARD_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import android.annotation.UserIdInt; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -66,6 +67,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; @@ -647,7 +649,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) { - if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) { + if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) { throw new IllegalStateException( "User " + userId + " must be unlocked for widgets to be available"); } @@ -692,6 +694,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku loadGroupStateLocked(newProfileIds); } + private boolean isUserRunningAndUnlocked(@UserIdInt int userId) { + return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, @@ -3358,7 +3364,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (userInfo != null && userInfo.isManagedProfile()) { UserInfo parentInfo = mUserManager.getProfileParent(userId); if (parentInfo != null - && !mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) { + && !isUserRunningAndUnlocked(parentInfo.getUserHandle().getIdentifier())) { return true; } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index dcd9b0c7e643..798662910cbf 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1443,6 +1443,12 @@ public final class ActiveServices { boolean allowCancel) { boolean canceled = false; + if (mAm.isShuttingDownLocked()) { + Slog.w(TAG, "Not scheduling restart of crashed service " + r.shortName + + " - system is shutting down"); + return false; + } + ServiceMap smap = getServiceMap(r.userId); if (smap.mServicesByName.get(r.name) != r) { ServiceRecord cur = smap.mServicesByName.get(r.name); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 402165ae2481..2f6eb462167b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -102,7 +102,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.app.admin.DevicePolicyManager; -import android.app.admin.DevicePolicyManagerInternal; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.IBackupManager; @@ -205,6 +204,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.DebugUtils; +import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.Pair; @@ -1513,6 +1513,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int NOTIFY_FORCED_RESIZABLE_MSG = 67; static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68; static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69; + static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1523,6 +1524,7 @@ public final class ActivityManagerService extends ActivityManagerNative static KillHandler sKillHandler = null; CompatModeDialog mCompatModeDialog; + UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog; long mLastMemUsageReportTime = 0; /** @@ -1693,6 +1695,22 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } + case SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG: { + synchronized (ActivityManagerService.this) { + final ActivityRecord ar = (ActivityRecord) msg.obj; + if (mUnsupportedDisplaySizeDialog != null) { + mUnsupportedDisplaySizeDialog.dismiss(); + mUnsupportedDisplaySizeDialog = null; + } + if (ar != null && mCompatModePackages.getPackageNotifyUnsupportedZoomLocked( + ar.packageName)) { + mUnsupportedDisplaySizeDialog = new UnsupportedDisplaySizeDialog( + ActivityManagerService.this, mContext, ar.info.applicationInfo); + mUnsupportedDisplaySizeDialog.show(); + } + } + break; + } case START_USER_SWITCH_UI_MSG: { mUserController.showUserSwitchDialog((Pair<UserInfo, UserInfo>) msg.obj); break; @@ -3099,6 +3117,16 @@ public final class ActivityManagerService extends ActivityManagerNative mUiHandler.sendMessage(msg); } + final void showUnsupportedZoomDialogIfNeededLocked(ActivityRecord r) { + if (mConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE + && r.appInfo.requiresSmallestWidthDp > mConfiguration.smallestScreenWidthDp) { + final Message msg = Message.obtain(); + msg.what = SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG; + msg.obj = r; + mUiHandler.sendMessage(msg); + } + } + private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index, String what, Object obj, ProcessRecord srcApp) { app.lastActivityTime = now; @@ -11476,11 +11504,15 @@ public final class ActivityManagerService extends ActivityManagerNative // Actually is sleeping or shutting down or whatever else in the future // is an inactive state. - public boolean isSleepingOrShuttingDown() { - return isSleeping() || mShuttingDown; + boolean isSleepingOrShuttingDownLocked() { + return isSleepingLocked() || mShuttingDown; + } + + boolean isShuttingDownLocked() { + return mShuttingDown; } - public boolean isSleeping() { + boolean isSleepingLocked() { return mSleeping; } @@ -12850,7 +12882,7 @@ public final class ActivityManagerService extends ActivityManagerNative proc.notCachedSinceIdle = true; proc.initialIdlePss = 0; proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true, - mTestPssMode, isSleeping(), now); + mTestPssMode, isSleepingLocked(), now); } } @@ -17763,6 +17795,14 @@ public final class ActivityManagerService extends ActivityManagerNative removeUriPermissionsForPackageLocked(ssp, userId, true); removeTasksByPackageNameLocked(ssp, userId); + + // Hide the "unsupported display" dialog if necessary. + if (mUnsupportedDisplaySizeDialog != null && ssp.equals( + mUnsupportedDisplaySizeDialog.getPackageName())) { + mUnsupportedDisplaySizeDialog.dismiss(); + mUnsupportedDisplaySizeDialog = null; + } + mCompatModePackages.handlePackageUninstalledLocked(ssp); mBatteryStatsService.notePackageUninstalled(ssp); } } else { @@ -17834,6 +17874,21 @@ public final class ActivityManagerService extends ActivityManagerNative } break; } + case Intent.ACTION_PACKAGE_DATA_CLEARED: + { + Uri data = intent.getData(); + String ssp; + if (data != null && (ssp = data.getSchemeSpecificPart()) != null) { + // Hide the "unsupported display" dialog if necessary. + if (mUnsupportedDisplaySizeDialog != null && ssp.equals( + mUnsupportedDisplaySizeDialog.getPackageName())) { + mUnsupportedDisplaySizeDialog.dismiss(); + mUnsupportedDisplaySizeDialog = null; + } + mCompatModePackages.handlePackageDataClearedLocked(ssp); + } + break; + } case Intent.ACTION_TIMEZONE_CHANGED: // If this is the time zone changed action, queue up a message that will reset // the timezone of all currently running processes. This message will get @@ -18656,6 +18711,9 @@ public final class ActivityManagerService extends ActivityManagerNative final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0; if (isDensityChange) { + // Reset the unsupported display size dialog. + mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG); + killAllBackgroundProcessesExcept(Build.VERSION_CODES.N, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); } @@ -19756,7 +19814,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) { app.pssProcState = app.setProcState; app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true, - mTestPssMode, isSleeping(), now); + mTestPssMode, isSleepingLocked(), now); mPendingPssProcesses.add(app); } } @@ -19804,7 +19862,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } return !processingBroadcasts - && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle()); + && (isSleepingLocked() || mStackSupervisor.allResumedActivitiesIdle()); } /** @@ -20095,7 +20153,7 @@ public final class ActivityManagerService extends ActivityManagerNative } app.lastStateTime = now; app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true, - mTestPssMode, isSleeping(), now); + mTestPssMode, isSleepingLocked(), now); if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from " + ProcessList.makeProcStateString(app.setProcState) + " to " + ProcessList.makeProcStateString(app.curProcState) + " next pss in " @@ -20106,7 +20164,7 @@ public final class ActivityManagerService extends ActivityManagerNative mTestPssMode)))) { requestPssLocked(app, app.setProcState); app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false, - mTestPssMode, isSleeping(), now); + mTestPssMode, isSleepingLocked(), now); } else if (false && DEBUG_PSS) Slog.d(TAG_PSS, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now)); } @@ -20632,7 +20690,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mLastMemoryLevel = memFactor; mLastNumProcesses = mLruProcesses.size(); - boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now); + boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleepingLocked(), now); final int trackerMemFactor = mProcessStats.getMemFactorLocked(); if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) { if (mLowRamStartTime == 0) { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 3ccac9e2f1e4..37d7c33a20d5 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -931,7 +931,7 @@ final class ActivityRecord { final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); boolean unsent = true; if ((state == ActivityState.RESUMED - || (service.isSleeping() && task.stack != null + || (service.isSleepingLocked() && task.stack != null && task.stack.topRunningActivityLocked() == this)) && app != null && app.thread != null) { try { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 0513b1ad8a8a..6af7a5db247e 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1075,7 +1075,7 @@ final class ActivityStack { if (mPausingActivity != null) { Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity + " state=" + mPausingActivity.state); - if (!mService.isSleeping()) { + if (!mService.isSleepingLocked()) { // Avoid recursion among check for sleep and complete pause during sleeping. // Because activity will be paused immediately after resume, just let pause // be completed by the order of activity paused from clients. @@ -1139,7 +1139,7 @@ final class ActivityStack { // If we are not going to sleep, we want to ensure the device is // awake until the next activity is started. - if (!uiSleeping && !mService.isSleepingOrShuttingDown()) { + if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) { mStackSupervisor.acquireLaunchWakelock(); } @@ -1292,7 +1292,7 @@ final class ActivityStack { // We don't need to schedule another stop, we only need to let it happen. prev.state = ActivityState.STOPPING; } else if ((!prev.visible && !hasVisibleBehindActivity()) - || mService.isSleepingOrShuttingDown()) { + || mService.isSleepingOrShuttingDownLocked()) { // If we were visible then resumeTopActivities will release resources before // stopping. addToStopping(prev, true /* immediate */); @@ -1310,7 +1310,7 @@ final class ActivityStack { if (resumeNext) { final ActivityStack topStack = mStackSupervisor.getFocusedStack(); - if (!mService.isSleepingOrShuttingDown()) { + if (!mService.isSleepingOrShuttingDownLocked()) { mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null); } else { mStackSupervisor.checkReadyForSleepLocked(); @@ -1821,7 +1821,7 @@ final class ActivityStack { boolean behindFullscreenActivity) { if (!okToShowLocked(r) - || (mService.isSleepingOrShuttingDown() && r.voiceSession == null)) { + || (mService.isSleepingOrShuttingDownLocked() && r.voiceSession == null)) { return false; } @@ -2196,7 +2196,7 @@ final class ActivityStack { // If we are sleeping, and there is no resumed activity, and the top // activity is paused, well that is the state we want. - if (mService.isSleepingOrShuttingDown() + if (mService.isSleepingOrShuttingDownLocked() && mLastPausedActivity == next && mStackSupervisor.allPausedActivitiesComplete()) { // Make sure we have executed any pending transitions, since there @@ -2278,7 +2278,7 @@ final class ActivityStack { // If the most recent activity was noHistory but was only stopped rather // than stopped+finished because the device went to sleep, we need to make // sure to finish it as we're making a new activity topmost. - if (mService.isSleeping() && mLastNoHistoryActivity != null && + if (mService.isSleepingLocked() && mLastNoHistoryActivity != null && !mLastNoHistoryActivity.finishing) { if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + mLastNoHistoryActivity + " on new resume"); @@ -2481,6 +2481,7 @@ final class ActivityStack { System.identityHashCode(next), next.task.taskId, next.shortComponentName); next.sleeping = false; + mService.showUnsupportedZoomDialogIfNeededLocked(next); mService.showAskCompatModeDialogLocked(next); next.app.pendingUiClean = true; next.app.forceProcessStateUpTo(mService.mTopProcessState); @@ -3212,7 +3213,7 @@ final class ActivityStack { if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) { if (!r.finishing) { - if (!mService.isSleeping()) { + if (!mService.isSleepingLocked()) { if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r); if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "stop-no-history", false)) { @@ -3244,7 +3245,7 @@ final class ActivityStack { EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags); - if (mService.isSleepingOrShuttingDown()) { + if (mService.isSleepingOrShuttingDownLocked()) { r.setSleeping(true); } Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 7a43d53d7021..738622fd923b 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1217,6 +1217,7 @@ public final class ActivityStackSupervisor implements DisplayListener { PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY); r.sleeping = false; r.forceNewConfig = false; + mService.showUnsupportedZoomDialogIfNeededLocked(r); mService.showAskCompatModeDialogLocked(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); ProfilerInfo profilerInfo = null; @@ -2707,7 +2708,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } void checkReadyForSleepLocked() { - if (!mService.isSleepingOrShuttingDown()) { + if (!mService.isSleepingOrShuttingDownLocked()) { // Do not care. return; } @@ -3047,7 +3048,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mWindowManager.setAppVisibility(s.appToken, false); } } - if ((!waitingVisible || mService.isSleepingOrShuttingDown()) && remove) { + if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) { if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s); if (stops == null) { stops = new ArrayList<>(); @@ -3771,7 +3772,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } break; case SLEEP_TIMEOUT_MSG: { synchronized (mService) { - if (mService.isSleepingOrShuttingDown()) { + if (mService.isSleepingOrShuttingDownLocked()) { Slog.w(TAG, "Sleep timeout! Sleeping now."); mSleepTimeout = true; checkReadyForSleepLocked(); diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java index 26264e5da147..a54df4bf069d 100644 --- a/services/core/java/com/android/server/am/CompatModePackages.java +++ b/services/core/java/com/android/server/am/CompatModePackages.java @@ -57,6 +57,8 @@ public final class CompatModePackages { public static final int COMPAT_FLAG_DONT_ASK = 1<<0; // Compatibility state: compatibility mode is enabled. public static final int COMPAT_FLAG_ENABLED = 1<<1; + // Unsupported zoom state: don't warn the user about unsupported zoom mode. + public static final int UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY = 1<<2; private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>(); @@ -147,6 +149,24 @@ public final class CompatModePackages { return flags != null ? flags : 0; } + public void handlePackageDataClearedLocked(String packageName) { + // User has explicitly asked to clear all associated data. + removePackage(packageName); + } + + public void handlePackageUninstalledLocked(String packageName) { + // Clear settings when app is uninstalled since this is an explicit + // signal from the user to remove the app and all associated data. + removePackage(packageName); + } + + private void removePackage(String packageName) { + if (mPackages.containsKey(packageName)) { + mPackages.remove(packageName); + scheduleWrite(); + } + } + public void handlePackageAddedLocked(String packageName, boolean updated) { ApplicationInfo ai = null; try { @@ -165,13 +185,17 @@ public final class CompatModePackages { // any current settings for it. if (!mayCompat && mPackages.containsKey(packageName)) { mPackages.remove(packageName); - mHandler.removeMessages(MSG_WRITE); - Message msg = mHandler.obtainMessage(MSG_WRITE); - mHandler.sendMessageDelayed(msg, 10000); + scheduleWrite(); } } } + private void scheduleWrite() { + mHandler.removeMessages(MSG_WRITE); + Message msg = mHandler.obtainMessage(MSG_WRITE); + mHandler.sendMessageDelayed(msg, 10000); + } + public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) { CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mConfiguration.screenLayout, mService.mConfiguration.smallestScreenWidthDp, @@ -207,6 +231,10 @@ public final class CompatModePackages { return (getPackageFlags(packageName)&COMPAT_FLAG_DONT_ASK) == 0; } + public boolean getPackageNotifyUnsupportedZoomLocked(String packageName) { + return (getPackageFlags(packageName)&UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY) == 0; + } + public void setFrontActivityAskCompatModeLocked(boolean ask) { ActivityRecord r = mService.getFocusedStack().topRunningActivityLocked(); if (r != null) { @@ -223,9 +251,21 @@ public final class CompatModePackages { } else { mPackages.remove(packageName); } - mHandler.removeMessages(MSG_WRITE); - Message msg = mHandler.obtainMessage(MSG_WRITE); - mHandler.sendMessageDelayed(msg, 10000); + scheduleWrite(); + } + } + + public void setPackageNotifyUnsupportedZoomLocked(String packageName, boolean notify) { + final int curFlags = getPackageFlags(packageName); + final int newFlags = notify ? (curFlags&~UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY) : + (curFlags|UNSUPPORTED_ZOOM_FLAG_DONT_NOTIFY); + if (curFlags != newFlags) { + if (newFlags != 0) { + mPackages.put(packageName, newFlags); + } else { + mPackages.remove(packageName); + } + scheduleWrite(); } } @@ -321,9 +361,7 @@ public final class CompatModePackages { // Need to get compatibility info in new state. ci = compatibilityInfoForPackageLocked(ai); - mHandler.removeMessages(MSG_WRITE); - Message msg = mHandler.obtainMessage(MSG_WRITE); - mHandler.sendMessageDelayed(msg, 10000); + scheduleWrite(); final ActivityStack stack = mService.getFocusedStack(); ActivityRecord starting = stack.restartPackage(packageName); diff --git a/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java new file mode 100644 index 000000000000..501cd6bbba6d --- /dev/null +++ b/services/core/java/com/android/server/am/UnsupportedDisplaySizeDialog.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 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.am; + +import com.android.internal.R; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.view.Window; +import android.view.WindowManager; +import android.widget.CheckBox; + +public class UnsupportedDisplaySizeDialog { + private final AlertDialog mDialog; + private final String mPackageName; + + public UnsupportedDisplaySizeDialog(final ActivityManagerService service, Context context, + ApplicationInfo appInfo) { + mPackageName = appInfo.packageName; + + final PackageManager pm = context.getPackageManager(); + final CharSequence label = appInfo.loadSafeLabel(pm); + final CharSequence message = context.getString( + R.string.unsupported_display_size_message, label); + + mDialog = new AlertDialog.Builder(context) + .setPositiveButton(R.string.ok, null) + .setMessage(message) + .setView(R.layout.unsupported_display_size_dialog_content) + .create(); + + // Ensure the content view is prepared. + mDialog.create(); + + final Window window = mDialog.getWindow(); + window.setType(WindowManager.LayoutParams.TYPE_PHONE); + + // DO NOT MODIFY. Used by CTS to verify the dialog is displayed. + window.getAttributes().setTitle("UnsupportedDisplaySizeDialog"); + + final CheckBox alwaysShow = (CheckBox) mDialog.findViewById(R.id.ask_checkbox); + alwaysShow.setChecked(true); + alwaysShow.setOnCheckedChangeListener((buttonView, isChecked) -> { + synchronized (service) { + service.mCompatModePackages.setPackageNotifyUnsupportedZoomLocked( + mPackageName, isChecked); + } + }); + } + + public String getPackageName() { + return mPackageName; + } + + public void show() { + mDialog.show(); + } + + public void dismiss() { + mDialog.dismiss(); + } +} diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 4589327c3cdb..4c515f0fc87e 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1303,14 +1303,16 @@ public class UserManagerService extends IUserManager.Stub { } if (mAppOpsService != null) { // We skip it until system-ready. - final long token = Binder.clearCallingIdentity(); - try { - mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId); - } catch (RemoteException e) { - Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); - } finally { - Binder.restoreCallingIdentity(token); - } + mHandler.post(new Runnable() { + @Override + public void run() { + try { + mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); + } + } + }); } propagateUserRestrictionsLR(userId, effective, prevAppliedRestrictions); |