Merge "Work on issue #29328569: NPE in " com.google.android.configupdater"" into nyc-dev
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f12c284..3c7eef5 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1779,9 +1779,10 @@
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 @@
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 81788da..ac21346 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@
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 bfde870..b6c830c 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 4e9a075..67793fd 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -118,6 +118,16 @@
/**
* @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 @@
@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 @@
}
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 @@
@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 19b1cf3..48bdcb2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1814,6 +1814,19 @@
+ 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 0000000..5e5cf00
--- /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 48744b6..b55a9b22 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 7e9b57c..d154b03 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 47d3113..954b049 100644
--- a/docs/html/ndk/downloads/index.jd
+++ b/docs/html/ndk/downloads/index.jd
@@ -332,35 +332,199 @@
<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>
+<dt>
+ Announcements
+</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
+<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 c5a0d48..211b64e 100644
--- a/docs/html/ndk/downloads/revision_history.jd
+++ b/docs/html/ndk/downloads/revision_history.jd
@@ -10,6 +10,44 @@
<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 b242111..ef8a652 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -280,6 +280,15 @@
</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 32fdb0a..80da297 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 ca8784e..293de51 100644
--- a/docs/html/topic/libraries/data-binding/index.jd
+++ b/docs/html/topic/libraries/data-binding/index.jd
@@ -18,7 +18,7 @@
<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 @@
<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 @@
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 @@
}
}
</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 @@
</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 @@
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 @@
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 @@
</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 @@
//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 @@
</p>
<pre>public class MyHandlers {
public void onClickFriend(View view) { ... }
- public void onClickEnemy(View view) { ... }
}
</pre>
<p>
@@ -365,14 +403,121 @@
<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 c984abe..f287f1b 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 @@
}
@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 @@
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 60c24d0..f060502 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.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 @@
});
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 23a3ca1..46e7277 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 @@
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 3830ac5..407453c 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 @@
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 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 87d6307..dd46779 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 @@
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 @@
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 @@
}
}
- @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 @@
}
@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 ce9bbf4..3d030f9 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.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 @@
// 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 @@
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 2ab6b5f..f84c5d0 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 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 @@
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 18191cf..0de5105 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 @@
}
@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 @@
}
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 91889d3..542b258 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 @@
= 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 @@
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 @@
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);
- setLockScreenAllowRemoteInput(remoteInput && remoteInputDpm);
+
+ 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;
+
+ 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 68e5d0b..fa57775 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.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 @@
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 @@
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 43f847c2..71ef1ea 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 @@
// 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 a30f507..c93377a 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.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 @@
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 @@
@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 94c98d6..de3864d 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 @@
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 @@
}
@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 4e0ddd6..2a30229 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.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.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 @@
}
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 @@
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 @@
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 334b228..930c151 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 @@
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 dcd9b0c..7986629 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 @@
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 9bebef4..e984112 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.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.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 @@
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 @@
static KillHandler sKillHandler = null;
CompatModeDialog mCompatModeDialog;
+ UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
long mLastMemUsageReportTime = 0;
/**
@@ -1693,6 +1695,22 @@
}
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 @@
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 @@
// 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;
}
- public boolean isSleeping() {
+ boolean isShuttingDownLocked() {
+ return mShuttingDown;
+ }
+
+ boolean isSleepingLocked() {
return mSleeping;
}
@@ -12846,7 +12878,7 @@
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
proc.nextPssTime = ProcessList.computeNextPssTime(proc.setProcState, true,
- mTestPssMode, isSleeping(), now);
+ mTestPssMode, isSleepingLocked(), now);
}
}
@@ -17038,11 +17070,22 @@
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
}
return !processingBroadcasts
- && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
+ && (isSleepingLocked() || mStackSupervisor.allResumedActivitiesIdle());
}
/**
@@ -20081,7 +20150,7 @@
}
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 @@
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 @@
}
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 3ccac9e..37d7c33 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 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 27145fc..6af7a5d 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 @@
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 @@
// 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 @@
// 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 @@
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 @@
boolean stackVisibleBehind, ActivityRecord visibleBehind,
boolean behindFullscreenActivity) {
- if (!okToShowLocked(r)) {
+ if (!okToShowLocked(r)
+ || (mService.isSleepingOrShuttingDownLocked() && r.voiceSession == null)) {
return false;
}
@@ -2195,7 +2196,7 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 7a43d53..738622fd 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 @@
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 @@
}
void checkReadyForSleepLocked() {
- if (!mService.isSleepingOrShuttingDown()) {
+ if (!mService.isSleepingOrShuttingDownLocked()) {
// Do not care.
return;
}
@@ -3047,7 +3048,7 @@
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 @@
} 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 522e42b..e425484 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 @@
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 26264e5..a54df4b 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 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 @@
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 @@
// 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 @@
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 @@
} 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 @@
// 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 0000000..501cd6b
--- /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 a85064b..4c515f0 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 @@
}
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 @@
*/
@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;