diff options
37 files changed, 851 insertions, 286 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index f12c284d68ff..3c7eef5eee64 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1779,9 +1779,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case START_BACKUP_AGENT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); + String packageName = data.readString(); int backupRestoreMode = data.readInt(); - boolean success = bindBackupAgent(info, backupRestoreMode); + int userId = data.readInt(); + boolean success = bindBackupAgent(packageName, backupRestoreMode, userId); reply.writeNoException(); reply.writeInt(success ? 1 : 0); return true; @@ -4448,13 +4449,14 @@ class ActivityManagerProxy implements IActivityManager return binder; } - public boolean bindBackupAgent(ApplicationInfo app, int backupRestoreMode) + public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - app.writeToParcel(data, 0); + data.writeString(packageName); data.writeInt(backupRestoreMode); + data.writeInt(userId); mRemote.transact(START_BACKUP_AGENT_TRANSACTION, data, reply, 0); reply.readException(); boolean success = reply.readInt() != 0; diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 81788da78e83..ac213461f578 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -250,7 +250,7 @@ public interface IActivityManager extends IInterface { public IBinder peekService(Intent service, String resolvedType, String callingPackage) throws RemoteException; - public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode) + public boolean bindBackupAgent(String packageName, int backupRestoreMode, int userId) throws RemoteException; public void clearPendingBackup() throws RemoteException; public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException; diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl index bfde8702338a..b6c830cf9840 100644 --- a/core/java/android/service/quicksettings/IQSTileService.aidl +++ b/core/java/android/service/quicksettings/IQSTileService.aidl @@ -15,15 +15,10 @@ */ package android.service.quicksettings; -import android.service.quicksettings.Tile; -import android.service.quicksettings.IQSService; - /** * @hide */ oneway interface IQSTileService { - void setQSService(in IQSService service); - void setQSTile(in Tile tile); void onTileAdded(); void onTileRemoved(); void onStartListening(); diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index 4e9a0751f2e3..67793fd041c6 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -118,6 +118,16 @@ public class TileService extends Service { /** * @hide */ + public static final String EXTRA_SERVICE = "service"; + + /** + * @hide + */ + public static final String EXTRA_TILE = "tile"; + + /** + * @hide + */ public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT"; private final H mHandler = new H(Looper.getMainLooper()); @@ -305,18 +315,11 @@ public class TileService extends Service { @Override public IBinder onBind(Intent intent) { + mTile = intent.getParcelableExtra(EXTRA_TILE); + mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE)); + mTile.setService(mService); return new IQSTileService.Stub() { @Override - public void setQSService(IQSService service) throws RemoteException { - mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget(); - } - - @Override - public void setQSTile(Tile tile) throws RemoteException { - mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget(); - } - - @Override public void onTileRemoved() throws RemoteException { mHandler.sendEmptyMessage(H.MSG_TILE_REMOVED); } @@ -349,14 +352,12 @@ public class TileService extends Service { } private class H extends Handler { - private static final int MSG_SET_TILE = 1; - private static final int MSG_START_LISTENING = 2; - private static final int MSG_STOP_LISTENING = 3; - private static final int MSG_TILE_ADDED = 4; - private static final int MSG_TILE_REMOVED = 5; - private static final int MSG_TILE_CLICKED = 6; - private static final int MSG_SET_SERVICE = 7; - private static final int MSG_UNLOCK_COMPLETE = 8; + private static final int MSG_START_LISTENING = 1; + private static final int MSG_STOP_LISTENING = 2; + private static final int MSG_TILE_ADDED = 3; + private static final int MSG_TILE_REMOVED = 4; + private static final int MSG_TILE_CLICKED = 5; + private static final int MSG_UNLOCK_COMPLETE = 6; public H(Looper looper) { super(looper); @@ -365,18 +366,6 @@ public class TileService extends Service { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_SET_SERVICE: - mService = (IQSService) msg.obj; - if (mTile != null) { - mTile.setService(mService); - } - break; - case MSG_SET_TILE: - mTile = (Tile) msg.obj; - if (mService != null && mTile != null) { - mTile.setService(mService); - } - break; case MSG_TILE_ADDED: TileService.this.onTileAdded(); break; 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/preview/support.jd b/docs/html/preview/support.jd index b2421119d117..ef8a65293d47 100644 --- a/docs/html/preview/support.jd +++ b/docs/html/preview/support.jd @@ -280,6 +280,15 @@ page.image=images/cards/card-n-support_2x.png </li> </ul> +<h4 id="">Android Auto</h4> + +<p> + The version of Google Maps included in Developer Preview 4 (9.30) crashes + when used with Android Auto. This issue will be fixed in the next update to + Google Maps (9.31), expected in the coming weeks. +</p> + + <!-- TBA, if any <h4>Device-specific issues</h4> 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/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 60c24d095aa7..f0605020c7d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -37,6 +37,7 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.TextView; + import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto; import com.android.systemui.R; @@ -227,6 +228,8 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta }); if (mNeedsFocus) { // Wait for this to get laid out then set its focus. + // Ensure that tile gets laid out so we get the callback. + holder.mTileView.requestLayout(); holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 23a3ca128de2..46e7277e36d4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -71,17 +71,12 @@ public class CustomTile extends QSTile<QSTile.State> implements TileChangeListen super(host); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mComponent = ComponentName.unflattenFromString(action); + mTile = new Tile(mComponent); + setTileIcon(); mServiceManager = host.getTileServices().getTileWrapper(this); mService = mServiceManager.getTileService(); mServiceManager.setTileChangeListener(this); - mTile = new Tile(mComponent); mUser = ActivityManager.getCurrentUser(); - setTileIcon(); - try { - mService.setQSTile(mTile); - } catch (RemoteException e) { - // Called through wrapper, won't happen here. - } } private void setTileIcon() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java index 3830ac50c60b..407453c6e3b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java @@ -35,16 +35,6 @@ public class QSTileServiceWrapper { return mService.asBinder(); } - public boolean setQSTile(Tile tile) { - try { - mService.setQSTile(tile); - return true; - } catch (Exception e) { - Log.d(TAG, "Caught exception from TileService", e); - return false; - } - } - public boolean onTileAdded() { try { mService.onTileAdded(); @@ -95,16 +85,6 @@ public class QSTileServiceWrapper { } } - public boolean setQSService(IQSService service) { - try { - mService.setQSService(service); - return true; - } catch (Exception e) { - Log.d(TAG, "Caught exception from TileService", e); - return false; - } - } - public boolean onUnlockComplete() { try { mService.onUnlockComplete(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 87d6307ffce2..dd467793d671 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -71,23 +71,24 @@ public class TileLifecycleManager extends BroadcastReceiver implements private Set<Integer> mQueuedMessages = new ArraySet<>(); private QSTileServiceWrapper mWrapper; private boolean mListening; - private Tile mTile; private IBinder mClickBinder; private int mBindTryCount; private boolean mBound; @VisibleForTesting boolean mReceiverRegistered; - private IQSService mService; private boolean mUnbindImmediate; private TileChangeListener mChangeListener; // Return value from bindServiceAsUser, determines whether safe to call unbind. private boolean mIsBound; - public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) { + public TileLifecycleManager(Handler handler, Context context, IQSService service, + Tile tile, Intent intent, UserHandle user) { mContext = context; mHandler = handler; mIntent = intent; + mIntent.putExtra(TileService.EXTRA_SERVICE, service.asBinder()); + mIntent.putExtra(TileService.EXTRA_TILE, tile); mUser = user; if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser); } @@ -164,14 +165,6 @@ public class TileLifecycleManager extends BroadcastReceiver implements service.linkToDeath(this, 0); } catch (RemoteException e) { } - if (!wrapper.setQSService(mService)) { - handleDeath(); - return; - } - if (!wrapper.setQSTile(mTile)) { - handleDeath(); - return; - } mWrapper = wrapper; handlePendingMessages(); } @@ -255,15 +248,6 @@ public class TileLifecycleManager extends BroadcastReceiver implements } } - @Override - public void setQSTile(Tile tile) { - if (DEBUG) Log.d(TAG, "setQSTile " + tile); - mTile = tile; - if (mWrapper != null && !mWrapper.setQSTile(tile)) { - handleDeath(); - } - } - private boolean checkComponentState() { PackageManager pm = mContext.getPackageManager(); if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) { @@ -347,14 +331,6 @@ public class TileLifecycleManager extends BroadcastReceiver implements } @Override - public void setQSService(IQSService service) { - mService = service; - if (mWrapper == null || !mWrapper.setQSService(service)) { - handleDeath(); - } - } - - @Override public void onTileAdded() { if (DEBUG) Log.d(TAG, "onTileAdded"); if (mWrapper == null || !mWrapper.onTileAdded()) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index ce9bbf42679a..3d030f977fbc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -27,6 +27,7 @@ import android.net.Uri; import android.os.Handler; import android.os.UserHandle; import android.service.quicksettings.IQSTileService; +import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; import android.support.annotation.VisibleForTesting; import android.util.Log; @@ -68,9 +69,10 @@ public class TileServiceManager { // This defaults to true to ensure tiles start out unavailable. private boolean mPendingBind = true; - TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) { + TileServiceManager(TileServices tileServices, Handler handler, ComponentName component, + Tile tile) { this(tileServices, handler, new TileLifecycleManager(handler, - tileServices.getContext(), new Intent().setComponent(component), + tileServices.getContext(), tileServices, tile, new Intent().setComponent(component), new UserHandle(ActivityManager.getCurrentUser()))); } @@ -80,7 +82,6 @@ public class TileServiceManager { mServices = tileServices; mHandler = handler; mStateManager = tileLifecycleManager; - mStateManager.setQSService(tileServices); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 2ab6b5fc98e9..f84c5d0bd717 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -78,7 +78,7 @@ public class TileServices extends IQSService.Stub { public TileServiceManager getTileWrapper(CustomTile tile) { ComponentName component = tile.getComponent(); - TileServiceManager service = onCreateTileService(component); + TileServiceManager service = onCreateTileService(component, tile.getQsTile()); synchronized (mServices) { mServices.put(tile, service); mTiles.put(component, tile); @@ -86,8 +86,8 @@ public class TileServices extends IQSService.Stub { return service; } - protected TileServiceManager onCreateTileService(ComponentName component) { - return new TileServiceManager(this, mHandler, component); + protected TileServiceManager onCreateTileService(ComponentName component, Tile tile) { + return new TileServiceManager(this, mHandler, component, tile); } public void freeService(CustomTile tile, TileServiceManager service) { 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/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 91889d3b91ad..542b25859036 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -134,6 +134,7 @@ public abstract class BaseStatusBar extends SystemUI implements = SystemProperties.getBoolean("debug.child_notifs", true); public static final boolean FORCE_REMOTE_INPUT_HISTORY = SystemProperties.getBoolean("debug.force_remoteinput_history", false); + private static boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false; protected static final int MSG_SHOW_RECENT_APPS = 1019; protected static final int MSG_HIDE_RECENT_APPS = 1020; @@ -704,10 +705,13 @@ public abstract class BaseStatusBar extends SystemUI implements Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false, mSettingsObserver, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), false, - mSettingsObserver, - UserHandle.USER_ALL); + if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT), + false, + mSettingsObserver, + UserHandle.USER_ALL); + } mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS), @@ -2304,16 +2308,20 @@ public abstract class BaseStatusBar extends SystemUI implements final boolean allowedByDpm = (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) == 0; - final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, - 0, - mCurrentUserId) != 0; - final boolean remoteInputDpm = (dpmFlags - & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0; + setShowLockscreenNotifications(show && allowedByDpm); + if (ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT) { + final boolean remoteInput = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, + 0, + mCurrentUserId) != 0; + final boolean remoteInputDpm = + (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) == 0; - setShowLockscreenNotifications(show && allowedByDpm); - setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm); + setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm); + } else { + setLockScreenAllowRemoteInput(false); + } } protected abstract void setAreThereNotifications(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 68e5d0b5bdd3..fa5777570b5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -29,6 +29,7 @@ import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Secure; +import android.service.quicksettings.Tile; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -399,10 +400,11 @@ public class QSTileHost implements QSTile.Host, Tunable { String tileSpec = previousTiles.get(i); if (!tileSpec.startsWith(CustomTile.PREFIX)) continue; if (!newTiles.contains(tileSpec)) { - Intent intent = new Intent().setComponent( - CustomTile.getComponentFromSpec(tileSpec)); + ComponentName component = CustomTile.getComponentFromSpec(tileSpec); + Intent intent = new Intent().setComponent(component); TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), - mContext, intent, new UserHandle(ActivityManager.getCurrentUser())); + mContext, mServices, new Tile(component), intent, + new UserHandle(ActivityManager.getCurrentUser())); lifecycleManager.onStopListening(); lifecycleManager.onTileRemoved(); lifecycleManager.flushMessagesAndUnbind(); @@ -412,10 +414,11 @@ public class QSTileHost implements QSTile.Host, Tunable { String tileSpec = newTiles.get(i); if (!tileSpec.startsWith(CustomTile.PREFIX)) continue; if (!previousTiles.contains(tileSpec)) { - Intent intent = new Intent().setComponent( - CustomTile.getComponentFromSpec(tileSpec)); + ComponentName component = CustomTile.getComponentFromSpec(tileSpec); + Intent intent = new Intent().setComponent(component); TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), - mContext, intent, new UserHandle(ActivityManager.getCurrentUser())); + mContext, mServices, new Tile(component), intent, + new UserHandle(ActivityManager.getCurrentUser())); lifecycleManager.onTileAdded(); lifecycleManager.flushMessagesAndUnbind(); } 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/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java index a30f50775f77..c93377a68f5d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java @@ -36,6 +36,8 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; import android.util.Log; +import org.mockito.Mockito; + @SmallTest public class TileLifecycleManagerTests extends AndroidTestCase { public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE"; @@ -54,8 +56,11 @@ public class TileLifecycleManagerTests extends AndroidTestCase { mThread = new HandlerThread("TestThread"); mThread.start(); mHandler = new Handler(mThread.getLooper()); + ComponentName component = new ComponentName(mContext, FakeTileService.class); mStateManager = new TileLifecycleManager(mHandler, getContext(), - new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId())); + Mockito.mock(IQSService.class), new Tile(component), + new Intent().setComponent(component), + new UserHandle(UserHandle.myUserId())); mCallbacks.clear(); getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST)); } @@ -251,16 +256,6 @@ public class TileLifecycleManagerTests extends AndroidTestCase { @Override public IBinder onBind(Intent intent) { return new IQSTileService.Stub() { - - @Override - public void setQSService(IQSService service) { - - } - - @Override - public void setQSTile(Tile tile) throws RemoteException { - } - @Override public void onTileAdded() throws RemoteException { sendCallback("onTileAdded"); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java index 94c98d6c5b9a..de3864dc1fef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java @@ -17,6 +17,7 @@ package com.android.systemui.qs.external; import android.content.ComponentName; import android.os.Looper; +import android.service.quicksettings.Tile; import android.test.suitebuilder.annotation.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.phone.QSTileHost; @@ -109,7 +110,7 @@ public class TileServicesTests extends SysuiTestCase { } @Override - protected TileServiceManager onCreateTileService(ComponentName component) { + protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) { TileServiceManager manager = Mockito.mock(TileServiceManager.class); mManagers.add(manager); return manager; 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/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 334b228a4ab7..930c151b1485 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -2356,7 +2356,8 @@ public class BackupManagerService { mConnecting = true; mConnectedAgent = null; try { - if (mActivityManager.bindBackupAgent(app, mode)) { + if (mActivityManager.bindBackupAgent(app.packageName, mode, + UserHandle.USER_OWNER)) { Slog.d(TAG, "awaiting agent for " + app); // success; wait for the agent to arrive 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 9bebef4c0e7d..e9841129c4c3 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; @@ -11472,11 +11500,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; } @@ -12846,7 +12878,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); } } @@ -17038,11 +17070,22 @@ public final class ActivityManagerService extends ActivityManagerNative // Cause the target app to be launched if necessary and its backup agent // instantiated. The backup agent will invoke backupAgentCreated() on the // activity manager to announce its creation. - public boolean bindBackupAgent(ApplicationInfo app, int backupMode) { - if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, - "bindBackupAgent: app=" + app + " mode=" + backupMode); + public boolean bindBackupAgent(String packageName, int backupMode, int userId) { + if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode); enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent"); + IPackageManager pm = AppGlobals.getPackageManager(); + ApplicationInfo app = null; + try { + app = pm.getApplicationInfo(packageName, 0, userId); + } catch (RemoteException e) { + // can't happen; package manager is process-local + } + if (app == null) { + Slog.w(TAG, "Unable to bind backup agent for " + packageName); + return false; + } + synchronized(this) { // !!! TODO: currently no check here that we're already bound BatteryStatsImpl.Uid.Pkg.Serv ss = null; @@ -17749,6 +17792,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 { @@ -17820,6 +17871,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 @@ -18642,6 +18708,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); } @@ -18711,7 +18780,7 @@ public final class ActivityManagerService extends ActivityManagerNative starting = mainStack.topRunningActivityLocked(); } - if (starting != null) { + if (starting != null && starting.state != ActivityState.STOPPED) { kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. @@ -19742,7 +19811,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); } } @@ -19790,7 +19859,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } return !processingBroadcasts - && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle()); + && (isSleepingLocked() || mStackSupervisor.allResumedActivitiesIdle()); } /** @@ -20081,7 +20150,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 " @@ -20092,7 +20161,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)); } @@ -20618,7 +20687,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 27145fc1a81a..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(); @@ -1820,7 +1820,8 @@ final class ActivityStack { boolean stackVisibleBehind, ActivityRecord visibleBehind, boolean behindFullscreenActivity) { - if (!okToShowLocked(r)) { + if (!okToShowLocked(r) + || (mService.isSleepingOrShuttingDownLocked() && r.voiceSession == null)) { return false; } @@ -2195,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 @@ -2277,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"); @@ -2480,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); @@ -3211,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)) { @@ -3243,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/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 522e42bda94b..e42548488ebe 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1465,14 +1465,23 @@ class ActivityStarter { intentActivity.task, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); mMovedToFront = true; - } else if ((launchStack.mStackId == DOCKED_STACK_ID - || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) - && (mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { - // If we want to launch adjacent and mTargetStack is not the computed - // launch stack - move task to top of computed stack. - mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId, - launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide", - ANIMATE); + } else if (launchStack.mStackId == DOCKED_STACK_ID + || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { + if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { + // If we want to launch adjacent and mTargetStack is not the computed + // launch stack - move task to top of computed stack. + mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId, + launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide", + ANIMATE); + } else { + // TODO: This should be reevaluated in MW v2. + // We choose to move task to front instead of launching it adjacent + // when specific stack was requested explicitly and it appeared to be + // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set. + mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation, + mOptions, mStartActivity.appTimeTracker, + "bringToFrontInsteadOfAdjacentLaunch"); + } mMovedToFront = true; } mOptions = null; 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 a85064b70f22..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); @@ -2296,7 +2298,7 @@ public class UserManagerService extends IUserManager.Stub { */ @Override public UserInfo createRestrictedProfile(String name, int parentUserId) { - checkManageUsersPermission("setupRestrictedProfile"); + checkManageOrCreateUsersPermission("setupRestrictedProfile"); final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId); if (user == null) { return null; |