diff options
104 files changed, 1876 insertions, 1230 deletions
@@ -146,6 +146,7 @@ LOCAL_SRC_FILES += \ core/java/android/database/IContentObserver.aidl \ core/java/android/hardware/ICameraService.aidl \ core/java/android/hardware/ICameraServiceListener.aidl \ + core/java/android/hardware/ICameraServiceProxy.aidl \ core/java/android/hardware/ICamera.aidl \ core/java/android/hardware/ICameraClient.aidl \ core/java/android/hardware/IConsumerIrService.aidl \ @@ -155,6 +156,8 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/display/IDisplayManager.aidl \ core/java/android/hardware/display/IDisplayManagerCallback.aidl \ core/java/android/hardware/display/IVirtualDisplayCallback.aidl \ + core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \ + core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \ core/java/android/hardware/fingerprint/IFingerprintService.aidl \ core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \ core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \ diff --git a/api/current.txt b/api/current.txt index 97db5aa..bbdb878 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5773,7 +5773,7 @@ package android.app.admin { method public void setPasswordMinimumSymbols(android.content.ComponentName, int); method public void setPasswordMinimumUpperCase(android.content.ComponentName, int); method public void setPasswordQuality(android.content.ComponentName, int); - method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean); + method public boolean setPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String, int); method public void setPermissionPolicy(android.content.ComponentName, int); method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>); method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>); @@ -5862,6 +5862,9 @@ package android.app.admin { field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000 field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000 field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0 + field public static final int PERMISSION_GRANT_STATE_DEFAULT = 0; // 0x0 + field public static final int PERMISSION_GRANT_STATE_DENIED = 2; // 0x2 + field public static final int PERMISSION_GRANT_STATE_GRANTED = 1; // 0x1 field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2 field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1 field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0 @@ -14798,8 +14801,8 @@ package android.media { ctor public AudioFormat.Builder(); ctor public AudioFormat.Builder(android.media.AudioFormat); method public android.media.AudioFormat build(); - method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException; - method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioFormat.Builder setChannelIndexMask(int); + method public android.media.AudioFormat.Builder setChannelMask(int); method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException; method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException; } @@ -14961,11 +14964,11 @@ package android.media { method public int getAudioFormat(); method public int getAudioSessionId(); method public int getAudioSource(); + method public int getBufferSizeInFrames(); method public int getChannelConfiguration(); method public int getChannelCount(); method public android.media.AudioFormat getFormat(); method public static int getMinBufferSize(int, int, int); - method public int getNativeFrameCount() throws java.lang.IllegalStateException; method public int getNotificationMarkerPosition(); method public int getPositionNotificationPeriod(); method public android.media.AudioDeviceInfo getPreferredDevice(); @@ -15034,13 +15037,14 @@ package android.media { method public void flush(); method public int getAudioFormat(); method public int getAudioSessionId(); + method public int getBufferSizeInFrames(); method public int getChannelConfiguration(); method public int getChannelCount(); method public android.media.AudioFormat getFormat(); method public static float getMaxVolume(); method public static int getMinBufferSize(int, int, int); method public static float getMinVolume(); - method public int getNativeFrameCount() throws java.lang.IllegalStateException; + method protected deprecated int getNativeFrameCount(); method public static int getNativeOutputSampleRate(int); method public int getNotificationMarkerPosition(); method public int getPlayState(); @@ -25176,13 +25180,6 @@ package android.provider { field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1 } - public static final class ContactsContract.Authorization { - ctor public ContactsContract.Authorization(); - field public static final java.lang.String AUTHORIZATION_METHOD = "authorize"; - field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri"; - field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize"; - } - protected static abstract interface ContactsContract.BaseSyncColumns { field public static final java.lang.String SYNC1 = "sync1"; field public static final java.lang.String SYNC2 = "sync2"; @@ -25589,6 +25586,8 @@ package android.provider { } protected static abstract interface ContactsContract.DataColumns { + field public static final java.lang.String CARRIER_PRESENCE = "carrier_presence"; + field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1 field public static final java.lang.String DATA1 = "data1"; field public static final java.lang.String DATA10 = "data10"; field public static final java.lang.String DATA11 = "data11"; @@ -25827,16 +25826,6 @@ package android.provider { field public static final android.net.Uri CONTENT_URI; } - public static final class ContactsContract.ProviderStatus { - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status"; - field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String STATUS = "status"; - field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3 - field public static final int STATUS_NORMAL = 0; // 0x0 - field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4 - field public static final int STATUS_UPGRADING = 1; // 0x1 - } - public static final class ContactsContract.QuickContact { ctor public ContactsContract.QuickContact(); method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]); diff --git a/api/system-current.txt b/api/system-current.txt index 10bf1ae..1a3673d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5882,7 +5882,7 @@ package android.app.admin { method public void setPasswordMinimumSymbols(android.content.ComponentName, int); method public void setPasswordMinimumUpperCase(android.content.ComponentName, int); method public void setPasswordQuality(android.content.ComponentName, int); - method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean); + method public boolean setPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String, int); method public void setPermissionPolicy(android.content.ComponentName, int); method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>); method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>); @@ -5976,6 +5976,9 @@ package android.app.admin { field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000 field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000 field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0 + field public static final int PERMISSION_GRANT_STATE_DEFAULT = 0; // 0x0 + field public static final int PERMISSION_GRANT_STATE_DENIED = 2; // 0x2 + field public static final int PERMISSION_GRANT_STATE_GRANTED = 1; // 0x1 field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2 field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1 field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0 @@ -16024,8 +16027,8 @@ package android.media { ctor public AudioFormat.Builder(); ctor public AudioFormat.Builder(android.media.AudioFormat); method public android.media.AudioFormat build(); - method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException; - method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioFormat.Builder setChannelIndexMask(int); + method public android.media.AudioFormat.Builder setChannelMask(int); method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException; method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException; } @@ -16197,11 +16200,11 @@ package android.media { method public int getAudioFormat(); method public int getAudioSessionId(); method public int getAudioSource(); + method public int getBufferSizeInFrames(); method public int getChannelConfiguration(); method public int getChannelCount(); method public android.media.AudioFormat getFormat(); method public static int getMinBufferSize(int, int, int); - method public int getNativeFrameCount() throws java.lang.IllegalStateException; method public int getNotificationMarkerPosition(); method public int getPositionNotificationPeriod(); method public android.media.AudioDeviceInfo getPreferredDevice(); @@ -16272,13 +16275,14 @@ package android.media { method public void flush(); method public int getAudioFormat(); method public int getAudioSessionId(); + method public int getBufferSizeInFrames(); method public int getChannelConfiguration(); method public int getChannelCount(); method public android.media.AudioFormat getFormat(); method public static float getMaxVolume(); method public static int getMinBufferSize(int, int, int); method public static float getMinVolume(); - method public int getNativeFrameCount() throws java.lang.IllegalStateException; + method protected deprecated int getNativeFrameCount(); method public static int getNativeOutputSampleRate(int); method public int getNotificationMarkerPosition(); method public int getPlayState(); @@ -27102,13 +27106,6 @@ package android.provider { field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1 } - public static final class ContactsContract.Authorization { - ctor public ContactsContract.Authorization(); - field public static final java.lang.String AUTHORIZATION_METHOD = "authorize"; - field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri"; - field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize"; - } - protected static abstract interface ContactsContract.BaseSyncColumns { field public static final java.lang.String SYNC1 = "sync1"; field public static final java.lang.String SYNC2 = "sync2"; @@ -27515,6 +27512,8 @@ package android.provider { } protected static abstract interface ContactsContract.DataColumns { + field public static final java.lang.String CARRIER_PRESENCE = "carrier_presence"; + field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1 field public static final java.lang.String DATA1 = "data1"; field public static final java.lang.String DATA10 = "data10"; field public static final java.lang.String DATA11 = "data11"; @@ -27753,16 +27752,6 @@ package android.provider { field public static final android.net.Uri CONTENT_URI; } - public static final class ContactsContract.ProviderStatus { - field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status"; - field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String STATUS = "status"; - field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3 - field public static final int STATUS_NORMAL = 0; // 0x0 - field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4 - field public static final int STATUS_UPGRADING = 1; // 0x1 - } - public static final class ContactsContract.QuickContact { ctor public ContactsContract.QuickContact(); method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 3309443..96c6878 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1366,7 +1366,9 @@ public class Notification implements Parcelable int version = parcel.readInt(); when = parcel.readLong(); - mSmallIcon = Icon.CREATOR.createFromParcel(parcel); + if (parcel.readInt() != 0) { + mSmallIcon = Icon.CREATOR.createFromParcel(parcel); + } number = parcel.readInt(); if (parcel.readInt() != 0) { contentIntent = PendingIntent.CREATOR.createFromParcel(parcel); @@ -1590,7 +1592,12 @@ public class Notification implements Parcelable parcel.writeInt(1); parcel.writeLong(when); - mSmallIcon.writeToParcel(parcel, 0); + if (mSmallIcon != null) { + parcel.writeInt(1); + mSmallIcon.writeToParcel(parcel, 0); + } else { + parcel.writeInt(0); + } parcel.writeInt(number); if (contentIntent != null) { parcel.writeInt(1); @@ -3241,7 +3248,7 @@ public class Notification implements Parcelable Notification n = new Notification(); n.when = mWhen; n.mSmallIcon = mSmallIcon; - if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) { + if (mSmallIcon != null && mSmallIcon.getType() == Icon.TYPE_RESOURCE) { n.icon = mSmallIcon.getResId(); } n.iconLevel = mSmallIconLevel; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 55ff85a..a8f2311 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -825,6 +825,23 @@ public class DevicePolicyManager { */ public static final int PERMISSION_POLICY_AUTO_DENY = 2; + /** + * Runtime permission state: The user can manage the permission + * through the UI. + */ + public static final int PERMISSION_GRANT_STATE_DEFAULT = 0; + + /** + * Runtime permission state: The permission is granted to the app + * and the user cannot manage the permission through the UI. + */ + public static final int PERMISSION_GRANT_STATE_GRANTED = 1; + + /** + * Runtime permission state: The permission is denied to the app + * and the user cannot manage the permission through the UI. + */ + public static final int PERMISSION_GRANT_STATE_DENIED = 2; /** * Return true if the given administrator component is currently @@ -4401,21 +4418,31 @@ public class DevicePolicyManager { } /** - * Grants or revokes a runtime permission to a specific application so that the user - * does not have to be prompted. This might affect all permissions in a group that the - * runtime permission belongs to. This method can only be called by a profile or device - * owner. + * Sets the grant state of a runtime permission for a specific application. The state + * can be {@link #PERMISSION_GRANT_STATE_DEFAULT default} in which a user can manage it + * through the UI, {@link #PERMISSION_GRANT_STATE_DENIED denied}, in which the permission + * is denied and the user cannot manage it through the UI, and {@link + * #PERMISSION_GRANT_STATE_GRANTED granted} in which the permission is granted and the + * user cannot manage it through the UI. This might affect all permissions in a + * group that the runtime permission belongs to. This method can only be called + * by a profile or device owner. + * * @param admin Which profile or device owner this request is associated with. * @param packageName The application to grant or revoke a permission to. * @param permission The permission to grant or revoke. - * @param granted Whether or not to grant the permission. If false, all permissions in the - * associated permission group will be denied. - * @return whether the permission was successfully granted or revoked + * @param grantState The permission grant state which is one of {@link + * #PERMISSION_GRANT_STATE_DENIED}, {@link #PERMISSION_GRANT_STATE_DEFAULT}, + * {@link #PERMISSION_GRANT_STATE_GRANTED}, + * @return whether the permission was successfully granted or revoked. + * + * @see #PERMISSION_GRANT_STATE_DENIED + * @see #PERMISSION_GRANT_STATE_DEFAULT + * @see #PERMISSION_GRANT_STATE_GRANTED */ - public boolean setPermissionGranted(ComponentName admin, String packageName, - String permission, boolean granted) { + public boolean setPermissionGrantState(ComponentName admin, String packageName, + String permission, int grantState) { try { - return mService.setPermissionGranted(admin, packageName, permission, granted); + return mService.setPermissionGrantState(admin, packageName, permission, grantState); } catch (RemoteException re) { Log.w(TAG, "Failed talking with device policy service", re); return false; diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 24ef604..10b0941 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -234,6 +234,6 @@ interface IDevicePolicyManager { void setPermissionPolicy(in ComponentName admin, int policy); int getPermissionPolicy(in ComponentName admin); - boolean setPermissionGranted(in ComponentName admin, String packageName, String permission, - boolean granted); + boolean setPermissionGrantState(in ComponentName admin, String packageName, + String permission, int grantState); } diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl index 9201b61..c933f92 100644 --- a/core/java/android/hardware/ICameraService.aidl +++ b/core/java/android/hardware/ICameraService.aidl @@ -25,7 +25,11 @@ import android.hardware.camera2.utils.BinderHolder; import android.hardware.ICameraServiceListener; import android.hardware.CameraInfo; -/** @hide */ +/** + * Binder interface for the native camera service running in mediaserver. + * + * @hide + */ interface ICameraService { /** diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl new file mode 100644 index 0000000..0bb24bc --- /dev/null +++ b/core/java/android/hardware/ICameraServiceProxy.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware; + +/** + * Binder interface for the camera service proxy running in system_server. + * + * @hide + */ +interface ICameraServiceProxy +{ + /** + * Ping the service proxy to update the valid users for the camera service. + */ + oneway void pingForUserUpdate(); +} diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 338bd76..caf21d5 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -729,12 +729,6 @@ public class FingerprintManager { } } - private void clearCallbacks() { - mAuthenticationCallback = null; - mEnrollmentCallback = null; - mRemovalCallback = null; - } - private void cancelEnrollment() { if (mService != null) try { mService.cancelEnrollment(mToken); diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl new file mode 100644 index 0000000..186d36e --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.fingerprint; + +import android.hardware.fingerprint.IFingerprintDaemonCallback; + +/** + * Communication channel from FingerprintService to FingerprintDaemon (fingerprintd) + * @hide + */ + +interface IFingerprintDaemon { + int authenticate(long sessionId, int groupId); + int cancelAuthentication(); + int enroll(in byte [] token, int groupId, int timeout); + int cancelEnrollment(); + long preEnroll(); + int remove(int fingerId, int groupId); + long getAuthenticatorId(); + int setActiveGroup(int groupId, in byte[] path); + long openHal(); + int closeHal(); + void init(IFingerprintDaemonCallback callback); +} diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl new file mode 100644 index 0000000..bd8ad6e --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.fingerprint; + +/** + * Communication channel from the fingerprintd back to FingerprintService. + * @hide + */ + interface IFingerprintDaemonCallback { + void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining); + void onAcquired(long deviceId, int acquiredInfo); + void onAuthenticated(long deviceId, int fingerId, int groupId); + void onError(long deviceId, int error); + void onRemoved(long deviceId, int fingerId, int groupId); + void onEnumerate(long deviceId, in int [] fingerIds, in int [] groupIds); +} diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 9c3a623..e6fc1ea 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -27,6 +27,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; /** * A Utility class for handling for communicating between bearer-specific @@ -51,6 +52,8 @@ public abstract class NetworkAgent extends Handler { private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>(); private volatile long mLastBwRefreshTime = 0; private static final long BW_REFRESH_MIN_WIN_MS = 500; + private boolean mPollLceScheduled = false; + private AtomicBoolean mPollLcePending = new AtomicBoolean(false); private static final int BASE = Protocol.BASE_NETWORK_AGENT; @@ -207,11 +210,23 @@ public abstract class NetworkAgent extends Handler { break; } case CMD_REQUEST_BANDWIDTH_UPDATE: { + long currentTimeMs = System.currentTimeMillis(); if (VDBG) { log("CMD_REQUEST_BANDWIDTH_UPDATE request received."); } - if (System.currentTimeMillis() > (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { - pollLceData(); + if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) { + mPollLceScheduled = false; + if (mPollLcePending.getAndSet(true) == false) { + pollLceData(); + } + } else { + // deliver the request at a later time rather than discard it completely. + if (!mPollLceScheduled) { + long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - + currentTimeMs + 1; + mPollLceScheduled = sendEmptyMessageDelayed( + CMD_REQUEST_BANDWIDTH_UPDATE, waitTime); + } } break; } @@ -260,6 +275,7 @@ public abstract class NetworkAgent extends Handler { * Called by the bearer code when it has new NetworkCapabilities data. */ public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { + mPollLcePending.set(false); mLastBwRefreshTime = System.currentTimeMillis(); queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilities(networkCapabilities)); diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index e07e846..76a5f967 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -230,6 +230,8 @@ public final class ContactsContract { * } * </pre> * </p> + * + * @hide */ public static final class Authorization { /** @@ -4067,6 +4069,21 @@ public final class ContactsContract { public static final String SYNC3 = "data_sync3"; /** Generic column for use by sync adapters. */ public static final String SYNC4 = "data_sync4"; + + /** + * Carrier presence information. + * <P> + * Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields) + * </P> + */ + public static final String CARRIER_PRESENCE = "carrier_presence"; + + /** + * Bitmask flags for CARRIER_PRESENCE column. Each value represents + * a bit (or a set of bits) which may be set independently of each + * other. + */ + public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01; } /** @@ -7913,6 +7930,8 @@ public final class ContactsContract { /** * API for inquiring about the general status of the provider. + * + * @hide */ public static final class ProviderStatus { @@ -8261,7 +8280,7 @@ public final class ContactsContract { /** * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager * to strip off anything not necessary. - * + * * @hide */ public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId, diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index d70712a..cdc196e 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -30,21 +30,21 @@ import android.util.Log; * <p>A TextureView can be used to display a content stream. Such a content * stream can for instance be a video or an OpenGL scene. The content stream * can come from the application's process as well as a remote process.</p> - * + * * <p>TextureView can only be used in a hardware accelerated window. When * rendered in software, TextureView will draw nothing.</p> - * + * * <p>Unlike {@link SurfaceView}, TextureView does not create a separate * window but behaves as a regular View. This key difference allows a * TextureView to be moved, transformed, animated, etc. For instance, you * can make a TextureView semi-translucent by calling * <code>myView.setAlpha(0.5f)</code>.</p> - * + * * <p>Using a TextureView is simple: all you need to do is get its * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to - * render content. The following example demonstrates how to render the + * render content. The following example demonstrates how to render the * camera preview into a TextureView:</p> - * + * * <pre> * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener { * private Camera mCamera; @@ -85,19 +85,19 @@ import android.util.Log; * } * } * </pre> - * + * * <p>A TextureView's SurfaceTexture can be obtained either by invoking * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}. * It is important to know that a SurfaceTexture is available only after the * TextureView is attached to a window (and {@link #onAttachedToWindow()} has * been invoked.) It is therefore highly recommended you use a listener to * be notified when the SurfaceTexture becomes available.</p> - * + * * <p>It is important to note that only one producer can use the TextureView. * For instance, if you use a TextureView to display the camera preview, you * cannot use {@link #lockCanvas()} to draw onto the TextureView at the same * time.</p> - * + * * @see SurfaceView * @see SurfaceTexture */ @@ -127,7 +127,7 @@ public class TextureView extends View { /** * Creates a new TextureView. - * + * * @param context The context to associate this view with. */ public TextureView(Context context) { @@ -137,7 +137,7 @@ public class TextureView extends View { /** * Creates a new TextureView. - * + * * @param context The context to associate this view with. * @param attrs The attributes of the XML tag that is inflating the view. */ @@ -148,7 +148,7 @@ public class TextureView extends View { /** * Creates a new TextureView. - * + * * @param context The context to associate this view with. * @param attrs The attributes of the XML tag that is inflating the view. * @param defStyleAttr An attribute in the current theme that contains a @@ -193,7 +193,7 @@ public class TextureView extends View { /** * Indicates whether the content of this TextureView is opaque. The * content is assumed to be opaque by default. - * + * * @param opaque True if the content of this TextureView is opaque, * false otherwise */ @@ -258,7 +258,7 @@ public class TextureView extends View { * considered to act as a hardware layer. The optional paint supplied to this * method will however be taken into account when rendering the content of * this TextureView. - * + * * @param layerType The ype of layer to use with this view, must be one of * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or * {@link #LAYER_TYPE_HARDWARE} @@ -297,7 +297,7 @@ public class TextureView extends View { /** * Subclasses of TextureView cannot do their own rendering * with the {@link Canvas} object. - * + * * @param canvas The Canvas to which the View is rendered. */ @Override @@ -312,7 +312,7 @@ public class TextureView extends View { /** * Subclasses of TextureView cannot do their own rendering * with the {@link Canvas} object. - * + * * @param canvas The Canvas to which the View is rendered. */ @Override @@ -435,7 +435,7 @@ public class TextureView extends View { return; } } - + mLayer.prepare(getWidth(), getHeight(), mOpaque); mLayer.updateSurfaceTexture(); @@ -449,17 +449,17 @@ public class TextureView extends View { * The specified transform applies to the underlying surface * texture and does not affect the size or position of the view * itself, only of its content.</p> - * + * * <p>Some transforms might prevent the content from drawing * all the pixels contained within this view's bounds. In such * situations, make sure this texture view is not marked opaque.</p> - * + * * @param transform The transform to apply to the content of * this view. - * - * @see #getTransform(android.graphics.Matrix) - * @see #isOpaque() - * @see #setOpaque(boolean) + * + * @see #getTransform(android.graphics.Matrix) + * @see #isOpaque() + * @see #setOpaque(boolean) */ public void setTransform(Matrix transform) { mMatrix.set(transform); @@ -469,14 +469,14 @@ public class TextureView extends View { /** * Returns the transform associated with this texture view. - * + * * @param transform The {@link Matrix} in which to copy the current * transform. Can be null. - * + * * @return The specified matrix if not null or a new {@link Matrix} * instance otherwise. - * - * @see #setTransform(android.graphics.Matrix) + * + * @see #setTransform(android.graphics.Matrix) */ public Matrix getTransform(Matrix transform) { if (transform == null) { @@ -499,21 +499,21 @@ public class TextureView extends View { * <p>Returns a {@link android.graphics.Bitmap} representation of the content * of the associated surface texture. If the surface texture is not available, * this method returns null.</p> - * + * * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} * pixel format and its dimensions are the same as this view's.</p> - * + * * <p><strong>Do not</strong> invoke this method from a drawing method * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> - * + * * <p>If an error occurs during the copy, an empty bitmap will be returned.</p> - * + * * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface * texture is not available or the width <= 0 or the height <= 0 - * - * @see #isAvailable() - * @see #getBitmap(android.graphics.Bitmap) - * @see #getBitmap(int, int) + * + * @see #isAvailable() + * @see #getBitmap(android.graphics.Bitmap) + * @see #getBitmap(int, int) */ public Bitmap getBitmap() { return getBitmap(getWidth(), getHeight()); @@ -523,24 +523,24 @@ public class TextureView extends View { * <p>Returns a {@link android.graphics.Bitmap} representation of the content * of the associated surface texture. If the surface texture is not available, * this method returns null.</p> - * + * * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} * pixel format.</p> - * + * * <p><strong>Do not</strong> invoke this method from a drawing method * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> - * + * * <p>If an error occurs during the copy, an empty bitmap will be returned.</p> - * + * * @param width The width of the bitmap to create * @param height The height of the bitmap to create - * + * * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface * texture is not available or width is <= 0 or height is <= 0 - * - * @see #isAvailable() - * @see #getBitmap(android.graphics.Bitmap) - * @see #getBitmap() + * + * @see #isAvailable() + * @see #getBitmap(android.graphics.Bitmap) + * @see #getBitmap() */ public Bitmap getBitmap(int width, int height) { if (isAvailable() && width > 0 && height > 0) { @@ -555,21 +555,21 @@ public class TextureView extends View { * bitmap. If the surface texture is not available, the copy is not executed. * The content of the surface texture will be scaled to fit exactly inside * the specified bitmap.</p> - * + * * <p><strong>Do not</strong> invoke this method from a drawing method * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> - * + * * <p>If an error occurs, the bitmap is left unchanged.</p> - * + * * @param bitmap The bitmap to copy the content of the surface texture into, * cannot be null, all configurations are supported - * + * * @return The bitmap specified as a parameter - * - * @see #isAvailable() - * @see #getBitmap(int, int) - * @see #getBitmap() - * + * + * @see #isAvailable() + * @see #getBitmap(int, int) + * @see #getBitmap() + * * @throws IllegalStateException if the hardware rendering context cannot be * acquired to capture the bitmap */ @@ -609,21 +609,21 @@ public class TextureView extends View { * to implement * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)} * to find out when the Surface is available for use.</p> - * + * * <p>The content of the Surface is never preserved between unlockCanvas() * and lockCanvas(), for this reason, every pixel within the Surface area * must be written. The only exception to this rule is when a dirty * rectangle is specified, in which case, non-dirty pixels will be * preserved.</p> - * + * * <p>This method can only be used if the underlying surface is not already * owned by another producer. For instance, if the TextureView is being used * to render the camera's preview you cannot invoke this method.</p> - * + * * @return A Canvas used to draw into the surface. - * - * @see #lockCanvas(android.graphics.Rect) - * @see #unlockCanvasAndPost(android.graphics.Canvas) + * + * @see #lockCanvas(android.graphics.Rect) + * @see #unlockCanvasAndPost(android.graphics.Canvas) */ public Canvas lockCanvas() { return lockCanvas(null); @@ -639,12 +639,12 @@ public class TextureView extends View { * available (see {@link #isAvailable()} or if the surface texture is * already connected to an image producer (for instance: the camera, * OpenGL, a media player, etc.) - * + * * @param dirty Area of the surface that will be modified. * @return A Canvas used to draw into the surface. - * - * @see #lockCanvas() + * + * @see #lockCanvas() * @see #unlockCanvasAndPost(android.graphics.Canvas) * @see #isAvailable() */ @@ -670,11 +670,11 @@ public class TextureView extends View { * current pixels will be shown on the screen, but its content is lost, * in particular there is no guarantee that the content of the Surface * will remain unchanged when lockCanvas() is called again. - * + * * @param canvas The Canvas previously returned by lockCanvas() - * + * * @see #lockCanvas() - * @see #lockCanvas(android.graphics.Rect) + * @see #lockCanvas(android.graphics.Rect) */ public void unlockCanvasAndPost(Canvas canvas) { if (mCanvas != null && canvas == mCanvas) { @@ -691,8 +691,8 @@ public class TextureView extends View { * Returns the {@link SurfaceTexture} used by this view. This method * may return null if the view is not attached to a window or if the surface * texture has not been initialized yet. - * - * @see #isAvailable() + * + * @see #isAvailable() */ public SurfaceTexture getSurfaceTexture() { return mSurface; @@ -730,9 +730,13 @@ public class TextureView extends View { } mSurface = surfaceTexture; - // If the view is visible, update the listener in the new surface to use - // the existing listener in the view. - if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) { + /* + * If the view is visible and we already made a layer, update the + * listener in the new surface to use the existing listener in the view. + * Otherwise this will be called when the view becomes visible or the + * layer is created + */ + if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) { mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler); } mUpdateSurface = true; @@ -742,8 +746,8 @@ public class TextureView extends View { /** * Returns the {@link SurfaceTextureListener} currently associated with this * texture view. - * - * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) + * + * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) * @see SurfaceTextureListener */ public SurfaceTextureListener getSurfaceTextureListener() { @@ -753,8 +757,8 @@ public class TextureView extends View { /** * Sets the {@link SurfaceTextureListener} used to listen to surface * texture events. - * - * @see #getSurfaceTextureListener() + * + * @see #getSurfaceTextureListener() * @see SurfaceTextureListener */ public void setSurfaceTextureListener(SurfaceTextureListener listener) { @@ -777,7 +781,7 @@ public class TextureView extends View { public static interface SurfaceTextureListener { /** * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use. - * + * * @param surface The surface returned by * {@link android.view.TextureView#getSurfaceTexture()} * @param width The width of the surface @@ -787,7 +791,7 @@ public class TextureView extends View { /** * Invoked when the {@link SurfaceTexture}'s buffers size changed. - * + * * @param surface The surface returned by * {@link android.view.TextureView#getSurfaceTexture()} * @param width The new width of the surface @@ -800,7 +804,7 @@ public class TextureView extends View { * If returns true, no rendering should happen inside the surface texture after this method * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}. * Most applications should return true. - * + * * @param surface The surface about to be destroyed */ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface); @@ -808,7 +812,7 @@ public class TextureView extends View { /** * Invoked when the specified {@link SurfaceTexture} is updated through * {@link SurfaceTexture#updateTexImage()}. - * + * * @param surface The surface just updated */ public void onSurfaceTextureUpdated(SurfaceTexture surface); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 7f243d3..e044f1e 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -148,7 +148,6 @@ public class ThreadedRenderer extends HardwareRenderer { mInitialized = true; updateEnabledState(surface); boolean status = nInitialize(mNativeProxy, surface); - surface.allocateBuffers(); return status; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c4f9209..41f906a 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1705,10 +1705,19 @@ public final class ViewRootImpl implements ViewParent, mFullRedrawNeeded = true; mPreviousTransparentRegion.setEmpty(); + // Only initialize up-front if transparent regions are not + // requested, otherwise defer to see if the entire window + // will be transparent if (mAttachInfo.mHardwareRenderer != null) { try { hwInitialized = mAttachInfo.mHardwareRenderer.initialize( mSurface); + if (hwInitialized && (host.mPrivateFlags + & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) { + // Don't pre-allocate if transparent regions + // are requested as they may not be needed + mSurface.allocateBuffers(); + } } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 7976ca4..f0c86e5 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -218,7 +218,7 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR, to = "TYPE_NAVIGATION_BAR"), @ViewDebug.IntToString(from = TYPE_VOLUME_OVERLAY, to = "TYPE_VOLUME_OVERLAY"), @ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS"), - @ViewDebug.IntToString(from = TYPE_HIDDEN_NAV_CONSUMER, to = "TYPE_HIDDEN_NAV_CONSUMER"), + @ViewDebug.IntToString(from = TYPE_INPUT_CONSUMER, to = "TYPE_INPUT_CONSUMER"), @ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"), @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"), @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"), @@ -490,12 +490,11 @@ public interface WindowManager extends ViewManager { public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21; /** - * Window type: Fake window to consume touch events when the navigation - * bar is hidden. + * Window type to consume input events when the systemUI bars are hidden. * In multiuser systems shows on all users' windows. * @hide */ - public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22; + public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22; /** * Window type: Dreams (screen saver) window, just above keyguard. diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 9199af1..1b759a3 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -373,12 +373,12 @@ public interface WindowManagerPolicy { } /** - * Representation of a "fake window" that the policy has added to the - * window manager to consume events. + * Representation of a input consumer that the policy has added to the + * window manager to consume input events going to windows below it. */ - public interface FakeWindow { + public interface InputConsumer { /** - * Remove the fake window from the window manager. + * Remove the input consumer from the window manager. */ void dismiss(); } @@ -402,13 +402,10 @@ public interface WindowManagerPolicy { public void reevaluateStatusBarVisibility(); /** - * Add a fake window to the window manager. This window sits - * at the top of the other windows and consumes events. + * Add a input consumer which will consume all input events going to any window below it. */ - public FakeWindow addFakeWindow(Looper looper, - InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen); + public InputConsumer addInputConsumer(Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory); /** * Returns a code that describes the current state of the lid switch. diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index f5a99d1..19184d6 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3495,6 +3495,10 @@ public class Editor { mIdealVerticalOffset = 0.7f * handleHeight; } + public float getIdealVerticalOffset() { + return mIdealVerticalOffset; + } + protected void updateDrawable() { final int offset = getCurrentCursorOffset(); final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset); @@ -3966,7 +3970,11 @@ public class Editor { @Override protected int getHotspotX(Drawable drawable, boolean isRtlRun) { - return isRtlRun ? 0 : drawable.getIntrinsicWidth(); + if (isRtlRun) { + return drawable.getIntrinsicWidth() / 4; + } else { + return (drawable.getIntrinsicWidth() * 3) / 4; + } } @Override @@ -4084,7 +4092,11 @@ public class Editor { @Override protected int getHotspotX(Drawable drawable, boolean isRtlRun) { - return isRtlRun ? drawable.getIntrinsicWidth() : 0; + if (isRtlRun) { + return (drawable.getIntrinsicWidth() * 3) / 4; + } else { + return drawable.getIntrinsicWidth() / 4; + } } @Override @@ -4271,6 +4283,7 @@ public class Editor { private int mStartOffset = -1; // Indicates whether the user is selecting text and using the drag accelerator. private boolean mDragAcceleratorActive; + private boolean mHaventMovedEnoughToStartDrag; SelectionModifierCursorController() { resetTouchOffsets(); @@ -4335,19 +4348,20 @@ public class Editor { public void onTouchEvent(MotionEvent event) { // This is done even when the View does not have focus, so that long presses can start // selection and tap can move cursor from this tap position. + final float eventX = event.getX(); + final float eventY = event.getY(); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - final float x = event.getX(); - final float y = event.getY(); // Remember finger down position, to be able to start selection from there. - mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y); + mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition( + eventX, eventY); // Double tap detection if (mGestureStayedInTapRegion) { if (mDoubleTap) { - final float deltaX = x - mDownPositionX; - final float deltaY = y - mDownPositionY; + final float deltaX = eventX - mDownPositionX; + final float deltaY = eventY - mDownPositionY; final float distanceSquared = deltaX * deltaX + deltaY * deltaY; ViewConfiguration viewConfiguration = ViewConfiguration.get( @@ -4355,16 +4369,17 @@ public class Editor { int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop(); boolean stayedInArea = distanceSquared < doubleTapSlop * doubleTapSlop; - if (stayedInArea && isPositionOnText(x, y)) { + if (stayedInArea && isPositionOnText(eventX, eventY)) { startSelectionActionModeWithSelectionAndStartDrag(); mDiscardNextActionUp = true; } } } - mDownPositionX = x; - mDownPositionY = y; + mDownPositionX = eventX; + mDownPositionY = eventY; mGestureStayedInTapRegion = true; + mHaventMovedEnoughToStartDrag = true; break; case MotionEvent.ACTION_POINTER_DOWN: @@ -4378,18 +4393,24 @@ public class Editor { break; case MotionEvent.ACTION_MOVE: - final ViewConfiguration viewConfiguration = ViewConfiguration.get( + final ViewConfiguration viewConfig = ViewConfiguration.get( mTextView.getContext()); + final int touchSlop = viewConfig.getScaledTouchSlop(); - if (mGestureStayedInTapRegion) { - final float deltaX = event.getX() - mDownPositionX; - final float deltaY = event.getY() - mDownPositionY; + if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) { + final float deltaX = eventX - mDownPositionX; + final float deltaY = eventY - mDownPositionY; final float distanceSquared = deltaX * deltaX + deltaY * deltaY; - int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop(); - - if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) { - mGestureStayedInTapRegion = false; + if (mGestureStayedInTapRegion) { + int doubleTapTouchSlop = viewConfig.getScaledDoubleTapTouchSlop(); + mGestureStayedInTapRegion = + distanceSquared <= doubleTapTouchSlop * doubleTapTouchSlop; + } + if (mHaventMovedEnoughToStartDrag) { + // We don't start dragging until the user has moved enough. + mHaventMovedEnoughToStartDrag = + distanceSquared <= touchSlop * touchSlop; } } @@ -4399,56 +4420,28 @@ public class Editor { } if (mStartOffset != -1) { - final int rawOffset = mTextView.getOffsetForPosition(event.getX(), - event.getY()); - int offset = rawOffset; - - // We don't start "dragging" until the user is past the initial word that - // gets selected on long press. - int firstWordStart = getWordStart(mStartOffset); - int firstWordEnd = getWordEnd(mStartOffset); - if (offset > firstWordEnd || offset < firstWordStart) { - - // Basically the goal in the below code is to have the highlight be - // offset so that your finger isn't covering the end point. - int fingerOffset = viewConfiguration.getScaledTouchSlop(); - float mx = event.getX(); - float my = event.getY(); - if (mx > fingerOffset) mx -= fingerOffset; - if (my > fingerOffset) my -= fingerOffset; - offset = mTextView.getOffsetForPosition(mx, my); - - // Perform the check for closeness at edge of view, if we're very close - // don't adjust the offset to be in front of the finger - otherwise the - // user can't select words at the edge. - if (mTextView.getWidth() - fingerOffset > mx) { - // We're going by word, so we need to make sure that the offset - // that we get is within this, so we'll get the previous boundary. - final WordIterator wordIterator = getWordIteratorWithText(); - - final int precedingOffset = wordIterator.preceding(offset); - if (mStartOffset < offset) { - // Expanding with bottom handle, in this case the selection end - // is before the finger. - offset = Math.max(precedingOffset - 1, 0); - } else { - // Expand with the start handle, in this case the selection - // start is before the finger. - if (precedingOffset == WordIterator.DONE) { - offset = 0; - } else { - offset = wordIterator.preceding(precedingOffset); - } - } + if (!mHaventMovedEnoughToStartDrag) { + // Offset the finger by the same vertical offset as the handles. This + // improves visibility of the content being selected by shifting + // the finger below the content. + final float fingerOffset = (mStartHandle != null) + ? mStartHandle.getIdealVerticalOffset() + : touchSlop; + int offset = + mTextView.getOffsetForPosition(eventX, eventY - fingerOffset); + int startOffset; + // Snap to word boundaries. + if (mStartOffset < offset) { + // Expanding with end handle. + offset = getWordEnd(offset); + startOffset = getWordStart(mStartOffset); + } else { + // Expanding with start handle. + offset = getWordStart(offset); + startOffset = getWordEnd(mStartOffset); } - if (offset == WordIterator.DONE) - offset = rawOffset; - - // Need to adjust start offset based on direction of movement. - int newStart = mStartOffset < offset ? getWordStart(mStartOffset) - : getWordEnd(mStartOffset); - Selection.setSelection((Spannable) mTextView.getText(), newStart, - offset); + Selection.setSelection((Spannable) mTextView.getText(), + startOffset, offset); } } break; diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java index b9a75d3..65dc743 100644 --- a/core/java/com/android/internal/logging/MetricsConstants.java +++ b/core/java/com/android/internal/logging/MetricsConstants.java @@ -208,7 +208,6 @@ public interface MetricsConstants { public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183; public static final int APPLICATIONS_HIGH_POWER_APPS = 184; public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185; - public static final int APPLICATIONS_MANAGE_ASSIST = 186; //aliases public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY; diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index 32b5b02..5144457 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -27,6 +27,10 @@ #define ENCODING_E_AC3 6 #define ENCODING_DTS 7 #define ENCODING_DTS_HD 8 +#define ENCODING_MP3 9 +#define ENCODING_AAC_LC 10 +#define ENCODING_AAC_HE_V1 11 +#define ENCODING_AAC_HE_V2 12 #define ENCODING_INVALID 0 #define ENCODING_DEFAULT 1 @@ -52,6 +56,14 @@ static inline audio_format_t audioFormatToNative(int audioFormat) return AUDIO_FORMAT_DTS; case ENCODING_DTS_HD: return AUDIO_FORMAT_DTS_HD; + case ENCODING_MP3: + return AUDIO_FORMAT_MP3; + case ENCODING_AAC_LC: + return AUDIO_FORMAT_AAC_LC; + case ENCODING_AAC_HE_V1: + return AUDIO_FORMAT_AAC_HE_V1; + case ENCODING_AAC_HE_V2: + return AUDIO_FORMAT_AAC_HE_V2; case ENCODING_DEFAULT: return AUDIO_FORMAT_DEFAULT; default: @@ -76,6 +88,14 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_DTS; case AUDIO_FORMAT_DTS_HD: return ENCODING_DTS_HD; + case AUDIO_FORMAT_MP3: + return ENCODING_MP3; + case AUDIO_FORMAT_AAC_LC: + return ENCODING_AAC_LC; + case AUDIO_FORMAT_AAC_HE_V1: + return ENCODING_AAC_HE_V1; + case AUDIO_FORMAT_AAC_HE_V2: + return ENCODING_AAC_HE_V2; case AUDIO_FORMAT_DEFAULT: return ENCODING_DEFAULT; default: diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 87b81d5..e5c4ba9 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -521,11 +521,11 @@ static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject t } // ---------------------------------------------------------------------------- -static jint android_media_AudioRecord_get_native_frame_count(JNIEnv *env, jobject thiz) { +static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env, jobject thiz) { sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); if (lpRecorder == NULL) { jniThrowException(env, "java/lang/IllegalStateException", - "Unable to retrieve AudioRecord pointer for getNativeFrameCount()"); + "Unable to retrieve AudioRecord pointer for frameCount()"); return (jint)AUDIO_JAVA_ERROR; } return lpRecorder->frameCount(); @@ -700,8 +700,8 @@ static JNINativeMethod gMethods[] = { (void *)android_media_AudioRecord_readInArray<jfloatArray>}, {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I", (void *)android_media_AudioRecord_readInDirectBuffer}, - {"native_get_native_frame_count", - "()I", (void *)android_media_AudioRecord_get_native_frame_count}, + {"native_get_buffer_size_in_frames", + "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames}, {"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos}, {"native_get_marker_pos","()I", (void *)android_media_AudioRecord_get_marker_pos}, {"native_set_pos_update_period", diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 595f9f0..4f451c7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -681,7 +681,7 @@ android:permissionGroup="android.permission-group.SENSORS" android:label="@string/permlab_useFingerprint" android:description="@string/permdesc_useFingerprint" - android:protectionLevel="dangerous" /> + android:protectionLevel="normal" /> <!-- ====================================================================== --> <!-- INSTALLTIME PERMISSIONS --> diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png Binary files differindex 1550b44..7ccb70a 100644 --- a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png +++ b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png Binary files differindex b309dfd..e65b89d 100644 --- a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png +++ b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png Binary files differindex b36a413..775f1bb 100644 --- a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png +++ b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png Binary files differindex afd0bd2..68fd053 100644 --- a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png +++ b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png Binary files differindex 58f8c43..b5c2a91 100644 --- a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png +++ b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png Binary files differindex 42a893d..6c6185c 100644 --- a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png +++ b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png Binary files differindex d0f274a..f0e32af 100644 --- a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png +++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png Binary files differindex f1f637a..260e090 100644 --- a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png +++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png Binary files differindex 643168f..a7a48b8 100644 --- a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png +++ b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png Binary files differindex e8f3aad..2c72f4f 100644 --- a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png +++ b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f790d74..c715652 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2142,8 +2142,9 @@ <!-- Keyguard component --> <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string> - <!-- This config is used to force VoiceInteractionService to start on certain low ram devices. --> - <bool name="config_forceEnableVoiceInteractionService">false</bool> + <!-- This config is used to force VoiceInteractionService to start on certain low ram devices. + It declares the package name of VoiceInteractionService that should be started. --> + <string translatable="false" name="config_forceVoiceInteractionServicePackage"></string> <!-- This config is ued to determine whether animations are allowed in low power mode. --> <bool name="config_allowAnimationsInLowPowerMode">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6124b5b..4b57a47 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -280,7 +280,6 @@ <java-symbol type="bool" name="config_enableScreenshotChord" /> <java-symbol type="bool" name="config_bluetooth_default_profiles" /> <java-symbol type="bool" name="config_enableWifiDisplay" /> - <java-symbol type="bool" name="config_forceEnableVoiceInteractionService" /> <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" /> <java-symbol type="bool" name="config_useDevInputEventForAudioJack" /> <java-symbol type="bool" name="config_safe_media_volume_enabled" /> @@ -560,6 +559,7 @@ <java-symbol type="string" name="chooseActivity" /> <java-symbol type="string" name="config_default_dns_server" /> <java-symbol type="string" name="config_ethernet_iface_regex" /> + <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> <java-symbol type="string" name="config_ntpServer" /> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index a999b71..8ad7c12 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1575,11 +1575,12 @@ public final class Bitmap implements Parcelable { */ public boolean sameAs(Bitmap other) { checkRecycled("Can't call sameAs on a recycled bitmap!"); + if (this == other) return true; + if (other == null) return false; if (other.isRecycled()) { throw new IllegalArgumentException("Can't compare to a recycled bitmap!"); } - return this == other || (other != null - && nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap)); + return nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap); } /** diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index f75d6a0..1030451 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -23,6 +23,7 @@ #include "Properties.h" #include "renderstate/RenderState.h" #include "ShadowTessellator.h" +#include "utils/GLUtils.h" #include <utils/Log.h> #include <utils/String8.h> @@ -276,6 +277,9 @@ void Caches::flush(FlushMode mode) { clearGarbage(); glFinish(); + // Errors during cleanup should be considered non-fatal, dump them and + // and move on. TODO: All errors or just errors like bad surface? + GLUtils::dumpGLErrors(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 6b8c780..a17904e 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -119,7 +119,6 @@ void DeferredLayerUpdater::doUpdateTexImage() { void DeferredLayerUpdater::detachSurfaceTexture() { if (mSurfaceTexture.get()) { - mRenderThread.eglManager().requireGlContext(); status_t err = mSurfaceTexture->detachFromContext(); if (err != 0) { // TODO: Elevate to fatal exception diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index e54fa5a..d7c8316 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -169,7 +169,8 @@ void RenderState::debugOverdraw(bool enable, bool clear) { void RenderState::requireGLContext() { assertOnGLThread(); - mRenderThread.eglManager().requireGlContext(); + LOG_ALWAYS_FATAL_IF(!mRenderThread.eglManager().hasEglContext(), + "No GL context!"); } void RenderState::assertOnGLThread() { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 8329cd4..706e14e 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -262,8 +262,6 @@ void CanvasContext::draw() { if (drew) { swapBuffers(dirty, width, height); - } else { - mEglManager.cancelFrame(); } // TODO: Use a fence for real completion? @@ -297,7 +295,6 @@ void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) { ATRACE_CALL(); DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; if (thread.eglManager().hasEglContext()) { - thread.eglManager().requireGlContext(); mode = DrawGlInfo::kModeProcess; } @@ -318,7 +315,6 @@ static void destroyPrefetechedNode(RenderNode* node) { void CanvasContext::freePrefetechedLayers() { if (mPrefetechedLayers.size()) { - requireGlContext(); std::for_each(mPrefetechedLayers.begin(), mPrefetechedLayers.end(), destroyPrefetechedNode); mPrefetechedLayers.clear(); } @@ -329,7 +325,6 @@ void CanvasContext::buildLayer(RenderNode* node) { if (!mEglManager.hasEglContext() || !mCanvas) { return; } - requireGlContext(); // buildLayer() will leave the tree in an unknown state, so we must stop drawing stopDrawing(); @@ -352,7 +347,6 @@ void CanvasContext::buildLayer(RenderNode* node) { } bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - requireGlContext(); layer->apply(); return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap); } @@ -360,7 +354,6 @@ bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) void CanvasContext::destroyHardwareResources() { stopDrawing(); if (mEglManager.hasEglContext()) { - requireGlContext(); freePrefetechedLayers(); mRootRenderNode->destroyHardwareResources(); Caches::getInstance().flush(Caches::kFlushMode_Layers); @@ -372,7 +365,6 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { if (!thread.eglManager().hasEglContext()) return; ATRACE_CALL(); - thread.eglManager().requireGlContext(); if (level >= TRIM_MEMORY_COMPLETE) { Caches::getInstance().flush(Caches::kFlushMode_Full); thread.eglManager().destroy(); @@ -382,7 +374,8 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { } void CanvasContext::runWithGlContext(RenderTask* task) { - requireGlContext(); + LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), + "GL context not initialized!"); task->run(); } @@ -391,10 +384,6 @@ Layer* CanvasContext::createTextureLayer() { return LayerRenderer::createTextureLayer(mRenderThread.renderState()); } -void CanvasContext::requireGlContext() { - mEglManager.requireGlContext(); -} - void CanvasContext::setTextureAtlas(RenderThread& thread, const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) { thread.eglManager().setTextureAtlas(buffer, map, mapSize); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 17917af..10e66e9 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -122,8 +122,6 @@ private: void swapBuffers(const SkRect& dirty, EGLint width, EGLint height); void requireSurface(); - void requireGlContext(); - void freePrefetechedLayers(); RenderThread& mRenderThread; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 6255f5e..c0e7c73 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -78,8 +78,7 @@ EglManager::EglManager(RenderThread& thread) , mAllowPreserveBuffer(load_dirty_regions_property()) , mCurrentSurface(EGL_NO_SURFACE) , mAtlasMap(nullptr) - , mAtlasMapSize(0) - , mInFrame(false) { + , mAtlasMapSize(0) { mCanSetPreserveBuffer = mAllowPreserveBuffer; ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false"); } @@ -101,7 +100,8 @@ void EglManager::initialize() { loadConfig(); createContext(); - usePBufferSurface(); + createPBufferSurface(); + makeCurrent(mPBufferSurface); mRenderThread.renderState().onGLContextCreated(); initAtlas(); } @@ -110,17 +110,6 @@ bool EglManager::hasEglContext() { return mEglDisplay != EGL_NO_DISPLAY; } -void EglManager::requireGlContext() { - LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "No EGL context"); - - if (!mInFrame) { - // We can't be certain about the state of the current surface (whether - // or not it is destroyed, for example), so err on the side of using - // the pbuffer surface which we fully control - usePBufferSurface(); - } -} - void EglManager::loadConfig() { EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; EGLint attribs[] = { @@ -173,7 +162,6 @@ void EglManager::setTextureAtlas(const sp<GraphicBuffer>& buffer, mAtlasMapSize = mapSize; if (hasEglContext()) { - usePBufferSurface(); initAtlas(); } } @@ -185,7 +173,7 @@ void EglManager::initAtlas() { } } -void EglManager::usePBufferSurface() { +void EglManager::createPBufferSurface() { LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "usePBufferSurface() called on uninitialized GlobalContext!"); @@ -193,7 +181,6 @@ void EglManager::usePBufferSurface() { EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs); } - makeCurrent(mPBufferSurface); } EGLSurface EglManager::createSurface(EGLNativeWindowType window) { @@ -217,8 +204,6 @@ void EglManager::destroySurface(EGLSurface surface) { void EglManager::destroy() { if (mEglDisplay == EGL_NO_DISPLAY) return; - usePBufferSurface(); - mRenderThread.renderState().onGLContextDestroyed(); eglDestroyContext(mEglDisplay, mEglContext); eglDestroySurface(mEglDisplay, mPBufferSurface); @@ -236,11 +221,10 @@ bool EglManager::makeCurrent(EGLSurface surface) { if (isCurrent(surface)) return false; if (surface == EGL_NO_SURFACE) { - // If we are setting EGL_NO_SURFACE we don't care about any of the potential - // return errors, which would only happen if mEglDisplay had already been - // destroyed in which case the current context is already NO_CONTEXT - eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) { + // Ensure we always have a valid surface & context + surface = mPBufferSurface; + } + if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) { LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface, egl_error_str()); } @@ -259,12 +243,10 @@ void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) { eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height); } eglBeginFrame(mEglDisplay, surface); - mInFrame = true; } bool EglManager::swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height) { - mInFrame = false; #if WAIT_FOR_GPU_COMPLETION { @@ -328,10 +310,6 @@ void EglManager::fence() { eglDestroySyncKHR(mEglDisplay, fence); } -void EglManager::cancelFrame() { - mInFrame = false; -} - bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false; diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 0855516..8881de6 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -36,9 +36,7 @@ public: void initialize(); bool hasEglContext(); - void requireGlContext(); - void usePBufferSurface(); EGLSurface createSurface(EGLNativeWindowType window); void destroySurface(EGLSurface surface); @@ -49,7 +47,6 @@ public: bool makeCurrent(EGLSurface surface); void beginFrame(EGLSurface surface, EGLint* width, EGLint* height); bool swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height); - void cancelFrame(); // Returns true iff the surface is now preserving buffers. bool setPreserveBuffer(EGLSurface surface, bool preserve); @@ -65,6 +62,7 @@ private: // EglContext is never destroyed, method is purposely not implemented ~EglManager(); + void createPBufferSurface(); void loadConfig(); void createContext(); void initAtlas(); @@ -84,12 +82,6 @@ private: sp<GraphicBuffer> mAtlasBuffer; int64_t* mAtlasMap; size_t mAtlasMapSize; - - // Whether or not we are in the middle of drawing a frame. This is used - // to avoid switching surfaces mid-frame if requireGlContext() is called - // TODO: Need to be better about surface/context management so that this isn't - // necessary - bool mInFrame; }; } /* namespace renderthread */ diff --git a/media/java/android/media/AudioDeviceCallback.java b/media/java/android/media/AudioDeviceCallback.java index d7fa492..d9f0037 100644 --- a/media/java/android/media/AudioDeviceCallback.java +++ b/media/java/android/media/AudioDeviceCallback.java @@ -17,16 +17,24 @@ package android.media; /** - * OnAudioDeviceConnectionListener defines the interface for notification listeners in the - * {@link AudioManager} + * AudioDeviceCallback defines the mechanism by which applications can receive notifications + * of audio device connection and disconnection events. + * @see AudioManager#registerAudioDeviceCallback. */ public abstract class AudioDeviceCallback { /** - * Called by the {@link AudioManager} to indicate that an audio device has been - * connected or disconnected. A listener will probably call the - * {@link AudioManager#getDevices} method to retrieve the current list of audio - * devices. + * Called by the {@link AudioManager} to indicate that one or more audio devices have been + * connected. + * @param addedDevices An array of {@link AudioDeviceInfo} objects corresponding to any + * newly added audio devices. */ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {} + + /** + * Called by the {@link AudioManager} to indicate that one or more audio devices have been + * disconnected. + * @param removedDevices An array of {@link AudioDeviceInfo} objects corresponding to any + * newly removed audio devices. + */ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {} } diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 2099bd0..431d37e 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -204,7 +204,7 @@ public final class AudioDeviceInfo { * @see AudioFormat */ public @NonNull int[] getEncodings() { - return mPort.formats(); + return AudioFormat.filterPublicFormats(mPort.formats()); } /** diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index a7e092f..16ae58c 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * The AudioFormat class is used to access a number of audio format and @@ -53,6 +54,22 @@ public class AudioFormat { public static final int ENCODING_DTS = 7; /** Audio data format: DTS HD compressed */ public static final int ENCODING_DTS_HD = 8; + /** Audio data format: MP3 compressed + * @hide + * */ + public static final int ENCODING_MP3 = 9; + /** Audio data format: AAC LC compressed + * @hide + * */ + public static final int ENCODING_AAC_LC = 10; + /** Audio data format: AAC HE V1 compressed + * @hide + * */ + public static final int ENCODING_AAC_HE_V1 = 11; + /** Audio data format: AAC HE V2 compressed + * @hide + * */ + public static final int ENCODING_AAC_HE_V2 = 12; /** Invalid audio channel configuration */ /** @deprecated Use {@link #CHANNEL_INVALID} instead. */ @@ -241,6 +258,27 @@ public class AudioFormat { case ENCODING_E_AC3: case ENCODING_DTS: case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: + return true; + default: + return false; + } + } + + /** @hide */ + public static boolean isPublicEncoding(int audioFormat) + { + switch (audioFormat) { + case ENCODING_PCM_8BIT: + case ENCODING_PCM_16BIT: + case ENCODING_PCM_FLOAT: + case ENCODING_AC3: + case ENCODING_E_AC3: + case ENCODING_DTS: + case ENCODING_DTS_HD: return true; default: return false; @@ -260,6 +298,10 @@ public class AudioFormat { case ENCODING_E_AC3: case ENCODING_DTS: case ENCODING_DTS_HD: + case ENCODING_MP3: + case ENCODING_AAC_LC: + case ENCODING_AAC_HE_V1: + case ENCODING_AAC_HE_V2: return false; case ENCODING_INVALID: default: @@ -267,6 +309,28 @@ public class AudioFormat { } } + /** + * Returns an array of public encoding values extracted from an array of + * encoding values. + * @hide + */ + public static int[] filterPublicFormats(int[] formats) { + if (formats == null) { + return null; + } + int[] myCopy = Arrays.copyOf(formats, formats.length); + int size = 0; + for (int i = 0; i < myCopy.length; i++) { + if (isPublicEncoding(myCopy[i])) { + if (size != i) { + myCopy[size] = myCopy[i]; + } + size++; + } + } + return Arrays.copyOf(myCopy, size); + } + /** @removed */ public AudioFormat() { @@ -503,7 +567,7 @@ public class AudioFormat { * if both channel index mask and channel position mask * are specified but do not have the same channel count. */ - public @NonNull Builder setChannelMask(int channelMask) throws IllegalArgumentException { + public @NonNull Builder setChannelMask(int channelMask) { if (channelMask == 0) { throw new IllegalArgumentException("Invalid zero channel mask"); } else if (/* channelMask != 0 && */ mChannelIndexMask != 0 && @@ -555,8 +619,7 @@ public class AudioFormat { * if both channel index mask and channel position mask * are specified but do not have the same channel count. */ - public @NonNull Builder setChannelIndexMask(int channelIndexMask) - throws IllegalArgumentException { + public @NonNull Builder setChannelIndexMask(int channelIndexMask) { if (channelIndexMask == 0) { throw new IllegalArgumentException("Invalid zero channel index mask"); } else if (/* channelIndexMask != 0 && */ mChannelMask != 0 && diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index e7013a5..316ccf6 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3713,11 +3713,18 @@ public class AudioManager { private final static int MSG_DEVICES_DEVICES_ADDED = 0; private final static int MSG_DEVICES_DEVICES_REMOVED = 1; + /** + * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. + */ private ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); /** + * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter + * the results list to only those device types they are interested in. + */ + /** * Specifies to the {@link AudioManager#getDevices(int)} method to include * source (i.e. input) audio devices. */ @@ -3747,21 +3754,25 @@ public class AudioManager { } /** - * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently - * connected to the system and meeting the criteria specified in the <code>flags</code> - * parameter. + * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices + * currently connected to the system and meeting the criteria specified in the + * <code>flags</code> parameter. * @param flags A set of bitflags specifying the criteria to test. - * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@lGET_DEVICES_CES_ALL}. + * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}. * @return A (possibly zero-length) array of AudioDeviceInfo objects. */ public AudioDeviceInfo[] getDevices(int flags) { return getDevicesStatic(flags); } + /** + * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo + * objects from the current (internal) AudioDevicePort list. + */ private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { - // figure out how many AudioDeviceInfo we need space for + // figure out how many AudioDeviceInfo we need space for... int numRecs = 0; for (AudioDevicePort port : ports) { if (checkFlags(port, flags)) { @@ -3769,7 +3780,7 @@ public class AudioManager { } } - // Now load them up + // Now load them up... AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; int slot = 0; for (AudioDevicePort port : ports) { @@ -3782,7 +3793,12 @@ public class AudioManager { } /* - * Calculate the list of ports that are in ports_B, but not in ports_A + * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by + * the add/remove callback mechanism to provide a list of the newly added or removed devices + * rather than the whole list and make the app figure it out. + * Note that calling this method with: + * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. + * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. */ private static AudioDeviceInfo[] calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { @@ -3811,6 +3827,7 @@ public class AudioManager { * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently * connected to the system and meeting the criteria specified in the <code>flags</code> * parameter. + * This is an internal function. The public API front is getDevices(int). * @param flags A set of bitflags specifying the criteria to test. * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}. * @return A (possibly zero-length) array of AudioDeviceInfo objects. @@ -3821,15 +3838,20 @@ public class AudioManager { int status = AudioManager.listAudioDevicePorts(ports); if (status != AudioManager.SUCCESS) { // fail and bail! - return new AudioDeviceInfo[0]; + return new AudioDeviceInfo[0]; // Always return an array. } return infoListFromPortList(ports, flags); } /** - * Adds an {@link AudioDeviceCallback} to receive notifications of changes + * Registers an {@link AudioDeviceCallback} object to receive notifications of changes * to the set of connected audio devices. + * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect + * notifications. + * @param handler Specifies the {@link Handler} object for the thread on which to execute + * the callback. If <code>null</code>, the {@link Handler} associated with the main + * {@link Looper} will be used. */ public void registerAudioDeviceCallback(AudioDeviceCallback callback, android.os.Handler handler) { @@ -3842,8 +3864,10 @@ public class AudioManager { } /** - * Removes an {@link AudioDeviceCallback} which has been previously registered + * Unregisters an {@link AudioDeviceCallback} object which has been previously registered * to receive notifications of changes to the set of connected audio devices. + * @param callback The {@link AudioDeviceCallback} object that was previously registered + * with {@link AudioManager#registerAudioDeviceCallback) to be unregistered. */ public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { synchronized (mDeviceCallbacks) { @@ -3854,7 +3878,8 @@ public class AudioManager { } /** - * Sends device list change notification to all listeners. + * Internal method to compute and generate add/remove messages and then send to any + * registered callbacks. */ private void broadcastDeviceListChange() { int status; @@ -3908,7 +3933,8 @@ public class AudioManager { /** * Callback method called upon audio patch list update. - * @param patchList the updated list of audio patches + * Note: We don't do anything with Patches at this time, so ignore this notification. + * @param patchList the updated list of audio patches. */ public void onAudioPatchListUpdate(AudioPatch[] patchList) {} diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index c0bc6d6..7eb1357 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -494,7 +494,7 @@ public class AudioRecord * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum * required buffer size for the successful creation of an AudioRecord instance. * Since bufferSizeInBytes may be internally increased to accommodate the source - * requirements, use {@link #getNativeFrameCount()} to determine the actual buffer size + * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size * in frames. * @param bufferSizeInBytes a value strictly greater than 0 * @return the same Builder instance. @@ -777,7 +777,7 @@ public class AudioRecord } /** - * Returns the "native frame count" of the <code>AudioRecord</code> buffer. + * Returns the frame count of the native <code>AudioRecord</code> buffer. * This is greater than or equal to the bufferSizeInBytes converted to frame units * specified in the <code>AudioRecord</code> constructor or Builder. * The native frame count may be enlarged to accommodate the requirements of the @@ -786,8 +786,8 @@ public class AudioRecord * @return current size in frames of the <code>AudioRecord</code> buffer. * @throws IllegalStateException */ - public int getNativeFrameCount() throws IllegalStateException { - return native_get_native_frame_count(); + public int getBufferSizeInFrames() { + return native_get_buffer_size_in_frames(); } /** @@ -1218,16 +1218,23 @@ public class AudioRecord //-------------------------------------------------------------------------- // (Re)Routing Info //-------------------- + /** + * Defines the interface by which applications can receive notifications of routing + * changes for the associated {@link AudioRecord}. + */ public interface OnRoutingChangedListener { /** * Called when the routing of an AudioRecord changes from either and explicit or - * policy rerouting. + * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from + * device. */ public void onRoutingChanged(AudioRecord audioRecord); } /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord. + * Note: The query is only valid if the AudioRecord is currently recording. If it is not, + * <code>getRoutedDevice()</code> will return null. */ public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); @@ -1245,8 +1252,9 @@ public class AudioRecord } /** - * The message sent to apps when the routing of this AudioRecord changes if they provide - * a {#link Handler} object to addOnRoutingChangeListener(). + * The list of AudioRecord.OnRoutingChangedListener interface added (with + * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)} + * by an app to receive (re)routing notifications. */ private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = @@ -1255,6 +1263,11 @@ public class AudioRecord /** * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes * on this AudioRecord. + * @param listener The {@link OnRoutingChangedListener} interface to receive notifications + * of rerouting events. + * @param handler Specifies the {@link Handler} object for the thread on which to execute + * the callback. If <code>null</code>, the {@link Handler} associated with the main + * {@link Looper} will be used. */ public void addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler) { @@ -1271,7 +1284,8 @@ public class AudioRecord /** * Removes an {@link OnRoutingChangedListener} which has been previously added - * to receive notifications of changes to the set of connected audio devices. + * to receive rerouting notifications. + * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. */ public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { synchronized (mRoutingChangeListeners) { @@ -1528,7 +1542,7 @@ public class AudioRecord private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes, boolean isBlocking); - private native final int native_get_native_frame_count(); + private native final int native_get_buffer_size_in_frames(); private native final int native_set_marker_pos(int marker); private native final int native_get_marker_pos(); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index d21762b..bd7a247 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -229,7 +229,7 @@ public class AudioTrack /** * Sizes of the native audio buffer. * These values are set during construction and can be stale. - * To obtain the current native audio buffer frame count use {@link #getNativeFrameCount()}. + * To obtain the current native audio buffer frame count use {@link #getBufferSizeInFrames()}. */ private int mNativeBufferSizeInBytes = 0; private int mNativeBufferSizeInFrames = 0; @@ -346,7 +346,7 @@ public class AudioTrack * If <code>bufferSizeInBytes</code> is less than the * minimum buffer size for the output sink, it is automatically increased to the minimum * buffer size. - * The method {@link #getNativeFrameCount()} returns the + * The method {@link #getBufferSizeInFrames()} returns the * actual size in frames of the native buffer created, which * determines the frequency to write * to the streaming <code>AudioTrack</code> to avoid underrun. @@ -775,7 +775,7 @@ public class AudioTrack audioFormat = AudioFormat.ENCODING_PCM_16BIT; } - if (!AudioFormat.isValidEncoding(audioFormat)) { + if (!AudioFormat.isPublicEncoding(audioFormat)) { throw new IllegalArgumentException("Unsupported audio encoding."); } mAudioFormat = audioFormat; @@ -1009,7 +1009,7 @@ public class AudioTrack } /** - * Returns the "native frame count" of the <code>AudioTrack</code> buffer. + * Returns the frame count of the native <code>AudioTrack</code> buffer. * <p> If the track's creation mode is {@link #MODE_STATIC}, * it is equal to the specified bufferSizeInBytes on construction, converted to frame units. * A static track's native frame count will not change. @@ -1019,12 +1019,26 @@ public class AudioTrack * the target output sink, and * if the track is subsequently routed to a different output sink, the native * frame count may enlarge to accommodate. - * See also {@link AudioManager#getProperty(String)} for key + * <p> If the <code>AudioTrack</code> encoding indicates compressed data, + * e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is + * the size of the native <code>AudioTrack</code> buffer in bytes. + * <p> See also {@link AudioManager#getProperty(String)} for key * {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}. - * @return current size in frames of the audio track buffer. + * @return current size in frames of the <code>AudioTrack</code> buffer. * @throws IllegalStateException */ - public int getNativeFrameCount() throws IllegalStateException { + public int getBufferSizeInFrames() { + return native_get_native_frame_count(); + } + + /** + * Returns the frame count of the native <code>AudioTrack</code> buffer. + * @return current size in frames of the <code>AudioTrack</code> buffer. + * @throws IllegalStateException + * @deprecated Use the identical public method {@link #getBufferSizeInFrames()} instead. + */ + @Deprecated + protected int getNativeFrameCount() { return native_get_native_frame_count(); } @@ -1119,7 +1133,7 @@ public class AudioTrack } } - if (!AudioFormat.isValidEncoding(audioFormat)) { + if (!AudioFormat.isPublicEncoding(audioFormat)) { loge("getMinBufferSize(): Invalid audio format."); return ERROR_BAD_VALUE; } @@ -1305,6 +1319,9 @@ public class AudioTrack * The valid sample rate range is from 1 Hz to twice the value returned by * {@link #getNativeOutputSampleRate(int)}. * Use {@link #setPlaybackParams(PlaybackParams)} for speed control. + * <p> This method may also be used to repurpose an existing <code>AudioTrack</code> + * for playback of content of differing sample rate, + * but with identical encoding and channel mask. * @param sampleRateInHz the sample rate expressed in Hz * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, * {@link #ERROR_INVALID_OPERATION} @@ -1474,7 +1491,7 @@ public class AudioTrack * <p> * If the mode is {@link #MODE_STREAM}, you can optionally prime the data path prior to * calling play(), by writing up to <code>bufferSizeInBytes</code> (from constructor). - * If you don’t call write() first, or if you call write() but with an insufficient amount of + * If you don't call write() first, or if you call write() but with an insufficient amount of * data, then the track will be in underrun state at play(). In this case, * playback will not actually start playing until the data path is filled to a * device-specific minimum level. This requirement for the path to be filled @@ -2153,16 +2170,23 @@ public class AudioTrack //-------------------------------------------------------------------------- // (Re)Routing Info //-------------------- + /** + * Defines the interface by which applications can receive notifications of routing + * changes for the associated {@link AudioTrack}. + */ public interface OnRoutingChangedListener { /** * Called when the routing of an AudioTrack changes from either and explicit or - * policy rerouting. + * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-to + * device. */ public void onRoutingChanged(AudioTrack audioTrack); } /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack. + * Note: The query is only valid if the AudioTrack is currently playing. If it is not, + * <code>getRoutedDevice()</code> will return null. */ public AudioDeviceInfo getRoutedDevice() { int deviceId = native_getRoutedDeviceId(); @@ -2180,8 +2204,9 @@ public class AudioTrack } /** - * The message sent to apps when the routing of this AudioTrack changes if they provide - * a {#link Handler} object to addOnRoutingChangedListener(). + * The list of AudioTrack.OnRoutingChangedListener interfaces added (with + * {@link AudioTrack#addOnRoutingChangedListener(OnRoutingChangedListener, android.os.Handler)} + * by an app to receive (re)routing notifications. */ private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = @@ -2190,6 +2215,11 @@ public class AudioTrack /** * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes * on this AudioTrack. + * @param listener The {@link OnRoutingChangedListener} interface to receive notifications + * of rerouting events. + * @param handler Specifies the {@link Handler} object for the thread on which to execute + * the callback. If <code>null</code>, the {@link Handler} associated with the main + * {@link Looper} will be used. */ public void addOnRoutingChangedListener(OnRoutingChangedListener listener, android.os.Handler handler) { @@ -2206,7 +2236,8 @@ public class AudioTrack /** * Removes an {@link OnRoutingChangedListener} which has been previously added - * to receive notifications of changes to the set of connected audio devices. + * to receive rerouting notifications. + * @param listener The previously added {@link OnRoutingChangedListener} interface to remove. */ public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) { synchronized (mRoutingChangeListeners) { diff --git a/packages/Keyguard/res/values-h650dp/dimens.xml b/packages/Keyguard/res/values-h650dp/dimens.xml index 92035bb..1cd2162 100644 --- a/packages/Keyguard/res/values-h650dp/dimens.xml +++ b/packages/Keyguard/res/values-h650dp/dimens.xml @@ -16,5 +16,5 @@ --> <resources> - <dimen name="widget_big_font_size">104dp</dimen> + <dimen name="widget_big_font_size">100dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5fece8d..5360645 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -361,9 +361,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId); return; } - if (groupId == userId) { - onFingerprintAuthenticated(groupId); - } + onFingerprintAuthenticated(userId); } finally { setFingerprintRunningDetectionRunning(false); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index ad710a6..1dba942 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -201,14 +201,14 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") private SettingsRegistry mSettingsRegistry; - @GuardedBy("mLock") - private UserManager mUserManager; + // We have to call in the user manager with no lock held, + private volatile UserManager mUserManager; - @GuardedBy("mLock") - private AppOpsManager mAppOpsManager; + // We have to call in the app ops manager with no lock held, + private volatile AppOpsManager mAppOpsManager; - @GuardedBy("mLock") - private PackageManager mPackageManager; + // We have to call in the package manager with no lock held, + private volatile PackageManager mPackageManager; @Override public boolean onCreate() { @@ -224,44 +224,46 @@ public class SettingsProvider extends ContentProvider { @Override public Bundle call(String method, String name, Bundle args) { - synchronized (mLock) { - final int requestingUserId = getRequestingUserId(args); - switch (method) { - case Settings.CALL_METHOD_GET_GLOBAL: { - Setting setting = getGlobalSettingLocked(name); - return packageValueForCallResult(setting); - } - - case Settings.CALL_METHOD_GET_SECURE: { - Setting setting = getSecureSettingLocked(name, requestingUserId); - return packageValueForCallResult(setting); - } + final int requestingUserId = getRequestingUserId(args); + switch (method) { + case Settings.CALL_METHOD_GET_GLOBAL: { + Setting setting = getGlobalSetting(name); + return packageValueForCallResult(setting); + } - case Settings.CALL_METHOD_GET_SYSTEM: { - Setting setting = getSystemSettingLocked(name, requestingUserId); - return packageValueForCallResult(setting); - } + case Settings.CALL_METHOD_GET_SECURE: { + Setting setting = getSecureSetting(name, requestingUserId); + return packageValueForCallResult(setting); + } - case Settings.CALL_METHOD_PUT_GLOBAL: { - String value = getSettingValue(args); - insertGlobalSettingLocked(name, value, requestingUserId); - } break; + case Settings.CALL_METHOD_GET_SYSTEM: { + Setting setting = getSystemSetting(name, requestingUserId); + return packageValueForCallResult(setting); + } - case Settings.CALL_METHOD_PUT_SECURE: { - String value = getSettingValue(args); - insertSecureSettingLocked(name, value, requestingUserId); - } break; + case Settings.CALL_METHOD_PUT_GLOBAL: { + String value = getSettingValue(args); + insertGlobalSetting(name, value, requestingUserId); + break; + } - case Settings.CALL_METHOD_PUT_SYSTEM: { - String value = getSettingValue(args); - insertSystemSettingLocked(name, value, requestingUserId); - } break; + case Settings.CALL_METHOD_PUT_SECURE: { + String value = getSettingValue(args); + insertSecureSetting(name, value, requestingUserId); + break; + } - default: { - Slog.w(LOG_TAG, "call() with invalid method: " + method); - } break; + case Settings.CALL_METHOD_PUT_SYSTEM: { + String value = getSettingValue(args); + insertSystemSetting(name, value, requestingUserId); + break; } + + default: { + Slog.w(LOG_TAG, "call() with invalid method: " + method); + } break; } + return null; } @@ -271,7 +273,7 @@ public class SettingsProvider extends ContentProvider { if (TextUtils.isEmpty(args.name)) { return "vnd.android.cursor.dir/" + args.table; } else { - return "vnd.android.cursor.item/" + args.table; + return "vnd.android.cursor.item/" + args.table; } } @@ -290,40 +292,38 @@ public class SettingsProvider extends ContentProvider { return new MatrixCursor(normalizedProjection, 0); } - synchronized (mLock) { - switch (args.table) { - case TABLE_GLOBAL: { - if (args.name != null) { - Setting setting = getGlobalSettingLocked(args.name); - return packageSettingForQuery(setting, normalizedProjection); - } else { - return getAllGlobalSettingsLocked(projection); - } + switch (args.table) { + case TABLE_GLOBAL: { + if (args.name != null) { + Setting setting = getGlobalSetting(args.name); + return packageSettingForQuery(setting, normalizedProjection); + } else { + return getAllGlobalSettings(projection); } + } - case TABLE_SECURE: { - final int userId = UserHandle.getCallingUserId(); - if (args.name != null) { - Setting setting = getSecureSettingLocked(args.name, userId); - return packageSettingForQuery(setting, normalizedProjection); - } else { - return getAllSecureSettingsLocked(userId, projection); - } + case TABLE_SECURE: { + final int userId = UserHandle.getCallingUserId(); + if (args.name != null) { + Setting setting = getSecureSetting(args.name, userId); + return packageSettingForQuery(setting, normalizedProjection); + } else { + return getAllSecureSettings(userId, projection); } + } - case TABLE_SYSTEM: { - final int userId = UserHandle.getCallingUserId(); - if (args.name != null) { - Setting setting = getSystemSettingLocked(args.name, userId); - return packageSettingForQuery(setting, normalizedProjection); - } else { - return getAllSystemSettingsLocked(userId, projection); - } + case TABLE_SYSTEM: { + final int userId = UserHandle.getCallingUserId(); + if (args.name != null) { + Setting setting = getSystemSetting(args.name, userId); + return packageSettingForQuery(setting, normalizedProjection); + } else { + return getAllSystemSettings(userId, projection); } + } - default: { - throw new IllegalArgumentException("Invalid Uri path:" + uri); - } + default: { + throw new IllegalArgumentException("Invalid Uri path:" + uri); } } } @@ -348,29 +348,27 @@ public class SettingsProvider extends ContentProvider { String value = values.getAsString(Settings.Secure.VALUE); - synchronized (mLock) { - switch (table) { - case TABLE_GLOBAL: { - if (insertGlobalSettingLocked(name, value, UserHandle.getCallingUserId())) { - return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name); - } - } break; - - case TABLE_SECURE: { - if (insertSecureSettingLocked(name, value, UserHandle.getCallingUserId())) { - return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); - } - } break; + switch (table) { + case TABLE_GLOBAL: { + if (insertGlobalSetting(name, value, UserHandle.getCallingUserId())) { + return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name); + } + } break; - case TABLE_SYSTEM: { - if (insertSystemSettingLocked(name, value, UserHandle.getCallingUserId())) { - return Uri.withAppendedPath(Settings.System.CONTENT_URI, name); - } - } break; + case TABLE_SECURE: { + if (insertSecureSetting(name, value, UserHandle.getCallingUserId())) { + return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); + } + } break; - default: { - throw new IllegalArgumentException("Bad Uri path:" + uri); + case TABLE_SYSTEM: { + if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) { + return Uri.withAppendedPath(Settings.System.CONTENT_URI, name); } + } break; + + default: { + throw new IllegalArgumentException("Bad Uri path:" + uri); } } @@ -412,26 +410,25 @@ public class SettingsProvider extends ContentProvider { return 0; } - synchronized (mLock) { - switch (args.table) { - case TABLE_GLOBAL: { - final int userId = UserHandle.getCallingUserId(); - return deleteGlobalSettingLocked(args.name, userId) ? 1 : 0; - } - case TABLE_SECURE: { - final int userId = UserHandle.getCallingUserId(); - return deleteSecureSettingLocked(args.name, userId) ? 1 : 0; - } + switch (args.table) { + case TABLE_GLOBAL: { + final int userId = UserHandle.getCallingUserId(); + return deleteGlobalSetting(args.name, userId) ? 1 : 0; + } - case TABLE_SYSTEM: { - final int userId = UserHandle.getCallingUserId(); - return deleteSystemSettingLocked(args.name, userId) ? 1 : 0; - } + case TABLE_SECURE: { + final int userId = UserHandle.getCallingUserId(); + return deleteSecureSetting(args.name, userId) ? 1 : 0; + } - default: { - throw new IllegalArgumentException("Bad Uri path:" + uri); - } + case TABLE_SYSTEM: { + final int userId = UserHandle.getCallingUserId(); + return deleteSystemSetting(args.name, userId) ? 1 : 0; + } + + default: { + throw new IllegalArgumentException("Bad Uri path:" + uri); } } } @@ -454,26 +451,24 @@ public class SettingsProvider extends ContentProvider { return 0; } - synchronized (mLock) { - switch (args.table) { - case TABLE_GLOBAL: { - final int userId = UserHandle.getCallingUserId(); - return updateGlobalSettingLocked(args.name, value, userId) ? 1 : 0; - } + switch (args.table) { + case TABLE_GLOBAL: { + final int userId = UserHandle.getCallingUserId(); + return updateGlobalSetting(args.name, value, userId) ? 1 : 0; + } - case TABLE_SECURE: { - final int userId = UserHandle.getCallingUserId(); - return updateSecureSettingLocked(args.name, value, userId) ? 1 : 0; - } + case TABLE_SECURE: { + final int userId = UserHandle.getCallingUserId(); + return updateSecureSetting(args.name, value, userId) ? 1 : 0; + } - case TABLE_SYSTEM: { - final int userId = UserHandle.getCallingUserId(); - return updateSystemSettingLocked(args.name, value, userId) ? 1 : 0; - } + case TABLE_SYSTEM: { + final int userId = UserHandle.getCallingUserId(); + return updateSystemSetting(args.name, value, userId) ? 1 : 0; + } - default: { - throw new IllegalArgumentException("Invalid Uri path:" + uri); - } + default: { + throw new IllegalArgumentException("Invalid Uri path:" + uri); } } } @@ -504,18 +499,18 @@ public class SettingsProvider extends ContentProvider { private void dumpForUser(int userId, PrintWriter pw) { if (userId == UserHandle.USER_OWNER) { pw.println("GLOBAL SETTINGS (user " + userId + ")"); - Cursor globalCursor = getAllGlobalSettingsLocked(ALL_COLUMNS); + Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS); dumpSettings(globalCursor, pw); pw.println(); } pw.println("SECURE SETTINGS (user " + userId + ")"); - Cursor secureCursor = getAllSecureSettingsLocked(userId, ALL_COLUMNS); + Cursor secureCursor = getAllSecureSettings(userId, ALL_COLUMNS); dumpSettings(secureCursor, pw); pw.println(); pw.println("SYSTEM SETTINGS (user " + userId + ")"); - Cursor systemCursor = getAllSystemSettingsLocked(userId, ALL_COLUMNS); + Cursor systemCursor = getAllSystemSettings(userId, ALL_COLUMNS); dumpSettings(systemCursor, pw); pw.println(); } @@ -575,64 +570,68 @@ public class SettingsProvider extends ContentProvider { UserHandle.ALL, true); } - private Cursor getAllGlobalSettingsLocked(String[] projection) { + private Cursor getAllGlobalSettings(String[] projection) { if (DEBUG) { - Slog.v(LOG_TAG, "getAllGlobalSettingsLocked()"); + Slog.v(LOG_TAG, "getAllGlobalSettings()"); } - // Get the settings. - SettingsState settingsState = mSettingsRegistry.getSettingsLocked( - SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); + synchronized (mLock) { + // Get the settings. + SettingsState settingsState = mSettingsRegistry.getSettingsLocked( + SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER); - List<String> names = settingsState.getSettingNamesLocked(); + List<String> names = settingsState.getSettingNamesLocked(); - final int nameCount = names.size(); + final int nameCount = names.size(); - String[] normalizedProjection = normalizeProjection(projection); - MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); + String[] normalizedProjection = normalizeProjection(projection); + MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); - // Anyone can get the global settings, so no security checks. - for (int i = 0; i < nameCount; i++) { - String name = names.get(i); - Setting setting = settingsState.getSettingLocked(name); - appendSettingToCursor(result, setting); - } + // Anyone can get the global settings, so no security checks. + for (int i = 0; i < nameCount; i++) { + String name = names.get(i); + Setting setting = settingsState.getSettingLocked(name); + appendSettingToCursor(result, setting); + } - return result; + return result; + } } - private Setting getGlobalSettingLocked(String name) { + private Setting getGlobalSetting(String name) { if (DEBUG) { Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")"); } // Get the value. - return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, - UserHandle.USER_OWNER, name); + synchronized (mLock) { + return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, + UserHandle.USER_OWNER, name); + } } - private boolean updateGlobalSettingLocked(String name, String value, int requestingUserId) { + private boolean updateGlobalSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "updateGlobalSettingLocked(" + name + ", " + value + ")"); + Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")"); } - return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); + return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); } - private boolean insertGlobalSettingLocked(String name, String value, int requestingUserId) { + private boolean insertGlobalSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "insertGlobalSettingLocked(" + name + ", " + value + ")"); + Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")"); } - return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT); + return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); } - private boolean deleteGlobalSettingLocked(String name, int requestingUserId) { + private boolean deleteGlobalSetting(String name, int requestingUserId) { if (DEBUG) { Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")"); } - return mutateGlobalSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE); + return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); } - private boolean mutateGlobalSettingLocked(String name, String value, int requestingUserId, + private boolean mutateGlobalSetting(String name, String value, int requestingUserId, int operation) { // Make sure the caller can change the settings - treated as secure. enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); @@ -651,28 +650,32 @@ public class SettingsProvider extends ContentProvider { } // Perform the mutation. - switch (operation) { - case MUTATION_OPERATION_INSERT: { - return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, - UserHandle.USER_OWNER, name, value, getCallingPackage()); - } + synchronized (mLock) { + switch (operation) { + case MUTATION_OPERATION_INSERT: { + return mSettingsRegistry + .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, + UserHandle.USER_OWNER, name, value, getCallingPackage()); + } - case MUTATION_OPERATION_DELETE: { - return mSettingsRegistry.deleteSettingLocked( - SettingsRegistry.SETTINGS_TYPE_GLOBAL, - UserHandle.USER_OWNER, name); - } + case MUTATION_OPERATION_DELETE: { + return mSettingsRegistry.deleteSettingLocked( + SettingsRegistry.SETTINGS_TYPE_GLOBAL, + UserHandle.USER_OWNER, name); + } - case MUTATION_OPERATION_UPDATE: { - return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, - UserHandle.USER_OWNER, name, value, getCallingPackage()); + case MUTATION_OPERATION_UPDATE: { + return mSettingsRegistry + .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL, + UserHandle.USER_OWNER, name, value, getCallingPackage()); + } } } return false; } - private Cursor getAllSecureSettingsLocked(int userId, String[] projection) { + private Cursor getAllSecureSettings(int userId, String[] projection) { if (DEBUG) { Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")"); } @@ -680,34 +683,36 @@ public class SettingsProvider extends ContentProvider { // Resolve the userId on whose behalf the call is made. final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId); - List<String> names = mSettingsRegistry.getSettingsNamesLocked( - SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId); + synchronized (mLock) { + List<String> names = mSettingsRegistry.getSettingsNamesLocked( + SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId); - final int nameCount = names.size(); + final int nameCount = names.size(); - String[] normalizedProjection = normalizeProjection(projection); - MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); + String[] normalizedProjection = normalizeProjection(projection); + MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); - for (int i = 0; i < nameCount; i++) { - String name = names.get(i); + for (int i = 0; i < nameCount; i++) { + String name = names.get(i); + // Determine the owning user as some profile settings are cloned from the parent. + final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, + name); - // Determine the owning user as some profile settings are cloned from the parent. - final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name); + // Special case for location (sigh). + if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) { + return null; + } - // Special case for location (sigh). - if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) { - return null; + Setting setting = mSettingsRegistry.getSettingLocked( + SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name); + appendSettingToCursor(result, setting); } - Setting setting = mSettingsRegistry.getSettingLocked( - SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name); - appendSettingToCursor(result, setting); + return result; } - - return result; } - private Setting getSecureSettingLocked(String name, int requestingUserId) { + private Setting getSecureSetting(String name, int requestingUserId) { if (DEBUG) { Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")"); } @@ -724,37 +729,39 @@ public class SettingsProvider extends ContentProvider { } // Get the value. - return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, - owningUserId, name); + synchronized (mLock) { + return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, + owningUserId, name); + } } - private boolean insertSecureSettingLocked(String name, String value, int requestingUserId) { + private boolean insertSecureSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "insertSecureSettingLocked(" + name + ", " + value + ", " + Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", " + requestingUserId + ")"); } - return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT); + return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); } - private boolean deleteSecureSettingLocked(String name, int requestingUserId) { + private boolean deleteSecureSetting(String name, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "deleteSecureSettingLocked(" + name + ", " + requestingUserId + ")"); + Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")"); } - return mutateSecureSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE); + return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); } - private boolean updateSecureSettingLocked(String name, String value, int requestingUserId) { + private boolean updateSecureSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "updateSecureSettingLocked(" + name + ", " + value + ", " + Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", " + requestingUserId + ")"); } - return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); + return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); } - private boolean mutateSecureSettingLocked(String name, String value, int requestingUserId, + private boolean mutateSecureSetting(String name, String value, int requestingUserId, int operation) { // Make sure the caller can change the settings. enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS); @@ -786,58 +793,65 @@ public class SettingsProvider extends ContentProvider { } // Mutate the value. - switch(operation) { - case MUTATION_OPERATION_INSERT: { - return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, - owningUserId, name, value, getCallingPackage()); - } + synchronized (mLock) { + switch (operation) { + case MUTATION_OPERATION_INSERT: { + return mSettingsRegistry + .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, + owningUserId, name, value, getCallingPackage()); + } - case MUTATION_OPERATION_DELETE: { - return mSettingsRegistry.deleteSettingLocked( - SettingsRegistry.SETTINGS_TYPE_SECURE, - owningUserId, name); - } + case MUTATION_OPERATION_DELETE: { + return mSettingsRegistry.deleteSettingLocked( + SettingsRegistry.SETTINGS_TYPE_SECURE, + owningUserId, name); + } - case MUTATION_OPERATION_UPDATE: { - return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, - owningUserId, name, value, getCallingPackage()); + case MUTATION_OPERATION_UPDATE: { + return mSettingsRegistry + .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE, + owningUserId, name, value, getCallingPackage()); + } } } return false; } - private Cursor getAllSystemSettingsLocked(int userId, String[] projection) { + private Cursor getAllSystemSettings(int userId, String[] projection) { if (DEBUG) { - Slog.v(LOG_TAG, "getAllSecureSystemLocked(" + userId + ")"); + Slog.v(LOG_TAG, "getAllSecureSystem(" + userId + ")"); } // Resolve the userId on whose behalf the call is made. final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId); - List<String> names = mSettingsRegistry.getSettingsNamesLocked( - SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId); + synchronized (mLock) { + List<String> names = mSettingsRegistry.getSettingsNamesLocked( + SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId); - final int nameCount = names.size(); + final int nameCount = names.size(); - String[] normalizedProjection = normalizeProjection(projection); - MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); + String[] normalizedProjection = normalizeProjection(projection); + MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount); - for (int i = 0; i < nameCount; i++) { - String name = names.get(i); + for (int i = 0; i < nameCount; i++) { + String name = names.get(i); - // Determine the owning user as some profile settings are cloned from the parent. - final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name); + // Determine the owning user as some profile settings are cloned from the parent. + final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, + name); - Setting setting = mSettingsRegistry.getSettingLocked( - SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name); - appendSettingToCursor(result, setting); - } + Setting setting = mSettingsRegistry.getSettingLocked( + SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name); + appendSettingToCursor(result, setting); + } - return result; + return result; + } } - private Setting getSystemSettingLocked(String name, int requestingUserId) { + private Setting getSystemSetting(String name, int requestingUserId) { if (DEBUG) { Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")"); } @@ -849,37 +863,39 @@ public class SettingsProvider extends ContentProvider { final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name); // Get the value. - return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, - owningUserId, name); + synchronized (mLock) { + return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, + owningUserId, name); + } } - private boolean insertSystemSettingLocked(String name, String value, int requestingUserId) { + private boolean insertSystemSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "insertSystemSettingLocked(" + name + ", " + value + ", " + Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", " + requestingUserId + ")"); } - return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT); + return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT); } - private boolean deleteSystemSettingLocked(String name, int requestingUserId) { + private boolean deleteSystemSetting(String name, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "deleteSystemSettingLocked(" + name + ", " + requestingUserId + ")"); + Slog.v(LOG_TAG, "deleteSystemSetting(" + name + ", " + requestingUserId + ")"); } - return mutateSystemSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE); + return mutateSystemSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE); } - private boolean updateSystemSettingLocked(String name, String value, int requestingUserId) { + private boolean updateSystemSetting(String name, String value, int requestingUserId) { if (DEBUG) { - Slog.v(LOG_TAG, "updateSystemSettingLocked(" + name + ", " + value + ", " + Slog.v(LOG_TAG, "updateSystemSetting(" + name + ", " + value + ", " + requestingUserId + ")"); } - return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); + return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE); } - private boolean mutateSystemSettingLocked(String name, String value, int runAsUserId, + private boolean mutateSystemSetting(String name, String value, int runAsUserId, int operation) { // Make sure the caller can change the settings. enforceWritePermission(Manifest.permission.WRITE_SETTINGS); @@ -904,27 +920,31 @@ public class SettingsProvider extends ContentProvider { } // Mutate the value. - switch (operation) { - case MUTATION_OPERATION_INSERT: { - validateSystemSettingValue(name, value); - return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, - owningUserId, name, value, getCallingPackage()); - } + synchronized (mLock) { + switch (operation) { + case MUTATION_OPERATION_INSERT: { + validateSystemSettingValue(name, value); + return mSettingsRegistry + .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, + owningUserId, name, value, getCallingPackage()); + } - case MUTATION_OPERATION_DELETE: { - return mSettingsRegistry.deleteSettingLocked( - SettingsRegistry.SETTINGS_TYPE_SYSTEM, - owningUserId, name); - } + case MUTATION_OPERATION_DELETE: { + return mSettingsRegistry.deleteSettingLocked( + SettingsRegistry.SETTINGS_TYPE_SYSTEM, + owningUserId, name); + } - case MUTATION_OPERATION_UPDATE: { - validateSystemSettingValue(name, value); - return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, - owningUserId, name, value, getCallingPackage()); + case MUTATION_OPERATION_UPDATE: { + validateSystemSettingValue(name, value); + return mSettingsRegistry + .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM, + owningUserId, name, value, getCallingPackage()); + } } - } - return false; + return false; + } } private void validateSystemSettingValue(String name, String value) { @@ -1043,6 +1063,7 @@ public class SettingsProvider extends ContentProvider { // user info is a cached instance, so just look up instead of cache. final long identity = Binder.clearCallingIdentity(); try { + // Just a lookup and not reentrant, so holding a lock is fine. UserInfo userInfo = mUserManager.getProfileParent(userId); return (userInfo != null) ? userInfo.id : userId; } finally { @@ -1088,7 +1109,7 @@ public class SettingsProvider extends ContentProvider { // skip prefix value = value.substring(1); - Setting settingValue = getSecureSettingLocked( + Setting settingValue = getSecureSetting( Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId); String oldProviders = (settingValue != null) ? settingValue.getValue() : ""; diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java index e71cf54..bb6bdbb 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java @@ -63,4 +63,10 @@ public abstract class AbstractAsset { throws AssociationServiceException { return AssetFactory.create(assetJson); } + + /** + * If this is the source asset of a statement file, should the retriever follow + * any insecure (non-HTTPS) include statements made by the asset. + */ + public abstract boolean followInsecureInclude(); } diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java index 0c96038..8ead90b 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java @@ -99,6 +99,12 @@ import java.util.Locale; return getPackageName().hashCode(); } + @Override + public boolean followInsecureInclude() { + // Non-HTTPS includes are not allowed in Android App assets. + return false; + } + /** * Checks that the input is a valid Android app asset. * diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java index 6516516..548149e 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java @@ -136,7 +136,8 @@ import java.util.List; } } - private Result retrieveStatementFromUrl(String url, int maxIncludeLevel, AbstractAsset source) + private Result retrieveStatementFromUrl(String urlString, int maxIncludeLevel, + AbstractAsset source) throws AssociationServiceException { List<Statement> statements = new ArrayList<Statement>(); if (maxIncludeLevel < 0) { @@ -145,7 +146,12 @@ import java.util.List; WebContent webContent; try { - webContent = mUrlFetcher.getWebContentFromUrl(new URL(url), + URL url = new URL(urlString); + if (!source.followInsecureInclude() + && !url.getProtocol().toLowerCase().equals("https")) { + return Result.create(statements, DO_NOT_CACHE_RESULT); + } + webContent = mUrlFetcher.getWebContentFromUrl(url, HTTP_CONTENT_SIZE_LIMIT_IN_BYTES, HTTP_CONNECTION_TIMEOUT_MILLIS); } catch (IOException e) { return Result.create(statements, DO_NOT_CACHE_RESULT); diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java index 4828ff9..969aa88 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java @@ -16,6 +16,8 @@ package com.android.statementservice.retriever; +import android.util.Log; + import com.android.volley.Cache; import com.android.volley.NetworkResponse; import com.android.volley.toolbox.HttpHeaderParser; @@ -39,6 +41,7 @@ import java.util.Map; * @hide */ public class URLFetcher { + private static final String TAG = URLFetcher.class.getSimpleName(); private static final long DO_NOT_CACHE_RESULT = 0L; private static final int INPUT_BUFFER_SIZE_IN_BYTES = 1024; @@ -63,11 +66,17 @@ public class URLFetcher { connection.setConnectTimeout(connectionTimeoutMillis); connection.setReadTimeout(connectionTimeoutMillis); connection.setUseCaches(true); + connection.setInstanceFollowRedirects(false); connection.addRequestProperty("Cache-Control", "max-stale=60"); + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode()); + return new WebContent("", DO_NOT_CACHE_RESULT); + } + if (connection.getContentLength() > fileSizeLimit) { - throw new AssociationServiceException("The content size of the url is larger than " - + fileSizeLimit); + Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit); + return new WebContent("", DO_NOT_CACHE_RESULT); } Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields()); diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java index 44af864..afb4c75 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java @@ -61,7 +61,7 @@ public final class Utils { */ public static final String ASSET_DESCRIPTOR_FIELD_RELATION = "relation"; public static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target"; - public static final String DELEGATE_FIELD_DELEGATE = "delegate"; + public static final String DELEGATE_FIELD_DELEGATE = "include"; private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java index ca9e62d..947087a 100644 --- a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java +++ b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java @@ -39,6 +39,7 @@ import java.util.Locale; /* package private */ final class WebAsset extends AbstractAsset { private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set."; + private static final String SCHEME_HTTP = "http"; private final URL mUrl; @@ -105,6 +106,12 @@ import java.util.Locale; return toJson().hashCode(); } + @Override + public boolean followInsecureInclude() { + // Only allow insecure include file if the asset scheme is http. + return SCHEME_HTTP.equals(getScheme()); + } + /** * Checks that the input is a valid web asset. * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java index 1186a33..9e5cefd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java @@ -99,7 +99,7 @@ public class ObservableScrollView extends ScrollView { } else if (!mTouchEnabled) { MotionEvent cancel = MotionEvent.obtain(ev); cancel.setAction(MotionEvent.ACTION_CANCEL); - super.dispatchTouchEvent(ev); + super.dispatchTouchEvent(cancel); cancel.recycle(); mTouchCancelled = true; return false; diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 01cc2ca..ff8fb83 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -88,13 +88,13 @@ import android.util.Slog; import android.util.SparseArray; import android.util.StringBuilderPrinter; +import com.android.internal.annotations.GuardedBy; import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.IObbBackupService; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; import com.android.server.SystemService; import com.android.server.backup.PackageManagerBackupAgent.Metadata; -import com.android.server.pm.PackageManagerService; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -589,8 +589,12 @@ public class BackupManagerService { File mFullBackupScheduleFile; // If we're running a schedule-driven full backup, this is the task instance doing it - PerformFullTransportBackupTask mRunningFullBackupTask; // inside mQueueLock - ArrayList<FullBackupEntry> mFullBackupQueue; // inside mQueueLock + + @GuardedBy("mQueueLock") + PerformFullTransportBackupTask mRunningFullBackupTask; + + @GuardedBy("mQueueLock") + ArrayList<FullBackupEntry> mFullBackupQueue; // Utility: build a new random integer token int generateToken() { @@ -1229,8 +1233,10 @@ public class BackupManagerService { } } - // Resume the full-data backup queue - mFullBackupQueue = readFullBackupSchedule(); + synchronized (mQueueLock) { + // Resume the full-data backup queue + mFullBackupQueue = readFullBackupSchedule(); + } // Register for broadcasts about package install, etc., so we can // update the provider list. @@ -1248,74 +1254,98 @@ public class BackupManagerService { } private ArrayList<FullBackupEntry> readFullBackupSchedule() { + boolean changed = false; ArrayList<FullBackupEntry> schedule = null; - synchronized (mQueueLock) { - if (mFullBackupScheduleFile.exists()) { - FileInputStream fstream = null; - BufferedInputStream bufStream = null; - DataInputStream in = null; - try { - fstream = new FileInputStream(mFullBackupScheduleFile); - bufStream = new BufferedInputStream(fstream); - in = new DataInputStream(bufStream); + List<PackageInfo> apps = + PackageManagerBackupAgent.getStorableApplications(mPackageManager); - int version = in.readInt(); - if (version != SCHEDULE_FILE_VERSION) { - Slog.e(TAG, "Unknown backup schedule version " + version); - return null; - } + if (mFullBackupScheduleFile.exists()) { + FileInputStream fstream = null; + BufferedInputStream bufStream = null; + DataInputStream in = null; + try { + fstream = new FileInputStream(mFullBackupScheduleFile); + bufStream = new BufferedInputStream(fstream); + in = new DataInputStream(bufStream); - int N = in.readInt(); - schedule = new ArrayList<FullBackupEntry>(N); - for (int i = 0; i < N; i++) { - String pkgName = in.readUTF(); - long lastBackup = in.readLong(); - try { - PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); - if (appGetsFullBackup(pkg) - && appIsEligibleForBackup(pkg.applicationInfo)) { - schedule.add(new FullBackupEntry(pkgName, lastBackup)); - } else { - if (DEBUG) { - Slog.i(TAG, "Package " + pkgName - + " no longer eligible for full backup"); - } - } - } catch (NameNotFoundException e) { + int version = in.readInt(); + if (version != SCHEDULE_FILE_VERSION) { + Slog.e(TAG, "Unknown backup schedule version " + version); + return null; + } + + final int N = in.readInt(); + schedule = new ArrayList<FullBackupEntry>(N); + + // HashSet instead of ArraySet specifically because we want the eventual + // lookups against O(hundreds) of entries to be as fast as possible, and + // we discard the set immediately after the scan so the extra memory + // overhead is transient. + HashSet<String> foundApps = new HashSet<String>(N); + + for (int i = 0; i < N; i++) { + String pkgName = in.readUTF(); + long lastBackup = in.readLong(); + foundApps.add(pkgName); // all apps that we've addressed already + try { + PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); + if (appGetsFullBackup(pkg) && appIsEligibleForBackup(pkg.applicationInfo)) { + schedule.add(new FullBackupEntry(pkgName, lastBackup)); + } else { if (DEBUG) { Slog.i(TAG, "Package " + pkgName - + " not installed; dropping from full backup"); + + " no longer eligible for full backup"); } } + } catch (NameNotFoundException e) { + if (DEBUG) { + Slog.i(TAG, "Package " + pkgName + + " not installed; dropping from full backup"); + } } - Collections.sort(schedule); - } catch (Exception e) { - Slog.e(TAG, "Unable to read backup schedule", e); - mFullBackupScheduleFile.delete(); - schedule = null; - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(bufStream); - IoUtils.closeQuietly(fstream); } - } - if (schedule == null) { - // no prior queue record, or unable to read it. Set up the queue - // from scratch. - List<PackageInfo> apps = - PackageManagerBackupAgent.getStorableApplications(mPackageManager); - final int N = apps.size(); - schedule = new ArrayList<FullBackupEntry>(N); - for (int i = 0; i < N; i++) { - PackageInfo info = apps.get(i); - if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { - schedule.add(new FullBackupEntry(info.packageName, 0)); + // New apps can arrive "out of band" via OTA and similar, so we also need to + // scan to make sure that we're tracking all full-backup candidates properly + for (PackageInfo app : apps) { + if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { + if (!foundApps.contains(app.packageName)) { + if (DEBUG) { + Slog.i(TAG, "New full backup app " + app.packageName + " found"); + } + schedule.add(new FullBackupEntry(app.packageName, 0)); + changed = true; + } } } - writeFullBackupScheduleAsync(); + + Collections.sort(schedule); + } catch (Exception e) { + Slog.e(TAG, "Unable to read backup schedule", e); + mFullBackupScheduleFile.delete(); + schedule = null; + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(bufStream); + IoUtils.closeQuietly(fstream); + } + } + + if (schedule == null) { + // no prior queue record, or unable to read it. Set up the queue + // from scratch. + changed = true; + schedule = new ArrayList<FullBackupEntry>(apps.size()); + for (PackageInfo info : apps) { + if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { + schedule.add(new FullBackupEntry(info.packageName, 0)); + } } } + + if (changed) { + writeFullBackupScheduleAsync(); + } return schedule; } @@ -4313,13 +4343,16 @@ public class BackupManagerService { // This is also slow but easy for modest numbers of apps: work backwards // from the end of the queue until we find an item whose last backup - // time was before this one, then insert this new entry after it. - int which; - for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { - final FullBackupEntry entry = mFullBackupQueue.get(which); - if (entry.lastBackup <= lastBackedUp) { - mFullBackupQueue.add(which + 1, newEntry); - break; + // time was before this one, then insert this new entry after it. If we're + // adding something new we don't bother scanning, and just prepend. + int which = -1; + if (lastBackedUp > 0) { + for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { + final FullBackupEntry entry = mFullBackupQueue.get(which); + if (entry.lastBackup <= lastBackedUp) { + mFullBackupQueue.add(which + 1, newEntry); + break; + } } } if (which < 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6842304..5a9b5b2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8884,7 +8884,8 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException("updateLockTaskPackage called from non-system process"); } synchronized (this) { - if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" + packages); + if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" + + Arrays.toString(packages)); mLockTaskPackages.put(userId, packages); mStackSupervisor.onLockTaskPackagesUpdatedLocked(); } @@ -8927,7 +8928,7 @@ public final class ActivityManagerService extends ActivityManagerNative mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ? ActivityManager.LOCK_TASK_MODE_PINNED : ActivityManager.LOCK_TASK_MODE_LOCKED, - "startLockTask"); + "startLockTask", true); } finally { Binder.restoreCallingIdentity(ident); } @@ -8992,7 +8993,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Stop lock task synchronized (this) { mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE, - "stopLockTask"); + "stopLockTask", true); } } finally { Binder.restoreCallingIdentity(ident); @@ -19433,7 +19434,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE, - "startUser"); + "startUser", false); final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId); if (userInfo == null) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f304828..5eee34f 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1185,7 +1185,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final TaskRecord task = r.task; if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { - setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE"); + setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false); } final ActivityStack stack = task.stack; @@ -3675,7 +3675,11 @@ public final class ActivityStackSupervisor implements DisplayListener { } void removeLockedTaskLocked(final TaskRecord task) { - if (mLockTaskModeTasks.remove(task) && mLockTaskModeTasks.isEmpty()) { + if (!mLockTaskModeTasks.remove(task)) { + return; + } + if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "removeLockedTaskLocked: removed " + task); + if (mLockTaskModeTasks.isEmpty()) { // Last one. if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task + " last task, reverting locktask mode. Callers=" + Debug.getCallers(3)); @@ -3696,7 +3700,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) { + void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason, + boolean andResume) { if (task == null) { // Take out of lock task mode if necessary final TaskRecord lockedTask = getLockedTaskLocked(); @@ -3745,8 +3750,11 @@ public final class ActivityStackSupervisor implements DisplayListener { if (task.mLockTaskUid == -1) { task.mLockTaskUid = task.mCallingUid; } - findTaskToMoveToFrontLocked(task, 0, null, reason); - resumeTopActivitiesLocked(); + + if (andResume) { + findTaskToMoveToFrontLocked(task, 0, null, reason); + resumeTopActivitiesLocked(); + } } boolean isLockTaskModeViolation(TaskRecord task) { @@ -3780,6 +3788,8 @@ public final class ActivityStackSupervisor implements DisplayListener { lockedTask.setLockTaskAuth(); if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) { // Lost whitelisting authorization. End it now. + if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " + + lockedTask + " mLockTaskAuth=" + lockedTask.lockTaskAuthToString()); removeLockedTaskLocked(lockedTask); lockedTask.performClearTaskLocked(); didSomething = true; @@ -3797,7 +3807,11 @@ public final class ActivityStackSupervisor implements DisplayListener { if (mLockTaskModeTasks.isEmpty() && task != null && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) { // This task must have just been authorized. - setLockTaskModeLocked(task, ActivityManager.LOCK_TASK_MODE_LOCKED, "package updated"); + if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, + "onLockTaskPackagesUpdated: starting new locktask task=" + task); + setLockTaskModeLocked(task, ActivityManager.LOCK_TASK_MODE_LOCKED, "package updated", + false); + didSomething = true; } if (didSomething) { resumeTopActivitiesLocked(); diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index 3a20ded..9f11def 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -435,9 +435,7 @@ class RecentTasks extends ArrayList<TaskRecord> { */ int trimForTaskLocked(TaskRecord task, boolean doTrim) { int recentsCount = size(); - final Intent intent = task.intent; - final boolean document = intent != null && intent.isDocument(); - + final boolean document = task.intent != null && task.intent.isDocument(); int maxRecents = task.maxRecents - 1; for (int i = 0; i < recentsCount; i++) { final TaskRecord tr = get(i); @@ -448,12 +446,11 @@ class RecentTasks extends ArrayList<TaskRecord> { if (i > MAX_RECENT_BITMAPS) { tr.freeLastThumbnail(); } - final Intent trIntent = tr.intent; - if ((task.affinity == null || !task.affinity.equals(tr.affinity)) && - (intent == null || !intent.filterEquals(trIntent))) { + if (task.realActivity == null || tr.realActivity == null || + !task.realActivity.equals(tr.realActivity)) { continue; } - final boolean trIsDocument = trIntent != null && trIntent.isDocument(); + final boolean trIsDocument = tr.intent != null && tr.intent.isDocument(); if (document && trIsDocument) { // These are the same document activity (not necessarily the same doc). if (maxRecents > 0) { diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 417c7c3..d56a024 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -739,38 +739,40 @@ final class TaskRecord { performClearTaskAtIndexLocked(0); } + String lockTaskAuthToString() { + switch (mLockTaskAuth) { + case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; + case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; + case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; + case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; + default: return "unknown=" + mLockTaskAuth; + } + } + void setLockTaskAuth() { switch (mLockTaskMode) { case LOCK_TASK_LAUNCH_MODE_DEFAULT: - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + - " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ? - "WHITELISTED" : "PINNABLE")); mLockTaskAuth = isLockTaskWhitelistedLocked() ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; break; case LOCK_TASK_LAUNCH_MODE_NEVER: - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + - " mLockTaskAuth=" + (mPrivileged ? "DONT_LOCK" : "PINNABLE")); mLockTaskAuth = mPrivileged ? LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE; break; case LOCK_TASK_LAUNCH_MODE_ALWAYS: - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + - " mLockTaskAuth=" + (mPrivileged ? "LAUNCHABLE" : "PINNABLE")); mLockTaskAuth = mPrivileged ? LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE; break; case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: - if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + - " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ? - "LAUNCHABLE" : "PINNABLE")); mLockTaskAuth = isLockTaskWhitelistedLocked() ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; break; } + if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + + " mLockTaskAuth=" + lockTaskAuthToString()); } boolean isLockTaskWhitelistedLocked() { @@ -1173,10 +1175,12 @@ final class TaskRecord { pw.print(" taskType="); pw.print(taskType); pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); } - if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) { + if (rootWasReset || mNeverRelinquishIdentity || mReuseTask + || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); - pw.print(" mReuseTask="); pw.println(mReuseTask); + pw.print(" mReuseTask="); pw.print(mReuseTask); + pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); } if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 9f35843..352c499 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4787,7 +4787,7 @@ public class AudioService extends IAudioService.Stub { if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI || devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) { // format the list of supported encodings - int[] formats = devicePort.formats(); + int[] formats = AudioFormat.filterPublicFormats(devicePort.formats()); if (formats.length > 0) { ArrayList<Integer> encodingList = new ArrayList(1); for (int format : formats) { diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java index 1d77bc2..777a9dd 100644 --- a/services/core/java/com/android/server/camera/CameraService.java +++ b/services/core/java/com/android/server/camera/CameraService.java @@ -19,6 +19,7 @@ import android.app.ActivityManager; import android.content.Context; import android.content.pm.UserInfo; import android.hardware.ICameraService; +import android.hardware.ICameraServiceProxy; import android.os.IBinder; import android.os.RemoteException; import android.os.UserManager; @@ -42,14 +43,30 @@ public class CameraService extends SystemService { */ private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera"; + public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy"; + // Event arguments to use with the camera service notifySystemEvent call: public static final int NO_EVENT = 0; // NOOP public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle private final Context mContext; private UserManager mUserManager; + + private final Object mLock = new Object(); private Set<Integer> mEnabledCameraUsers; + private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { + @Override + public void pingForUserUpdate() { + // Binder call + synchronized(mLock) { + if (mEnabledCameraUsers != null) { + notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers); + } + } + } + }; + public CameraService(Context context) { super(context); mContext = context; @@ -62,18 +79,27 @@ public class CameraService extends SystemService { // Should never see this unless someone messes up the SystemServer service boot order. throw new IllegalStateException("UserManagerService must start before CameraService!"); } + publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); } @Override public void onStartUser(int userHandle) { - if (mEnabledCameraUsers == null) { - // Initialize mediaserver, or update mediaserver if we are recovering from a crash. - onSwitchUser(userHandle); + synchronized(mLock) { + if (mEnabledCameraUsers == null) { + // Initialize mediaserver, or update mediaserver if we are recovering from a crash. + switchUserLocked(userHandle); + } } } @Override public void onSwitchUser(int userHandle) { + synchronized(mLock) { + switchUserLocked(userHandle); + } + } + + private void switchUserLocked(int userHandle) { Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) { // Some user handles have been added or removed, update mediaserver. @@ -82,7 +108,6 @@ public class CameraService extends SystemService { } } - private Set<Integer> getEnabledUserHandles(int currentUserHandle) { List<UserInfo> userProfiles = mUserManager.getEnabledProfiles(currentUserHandle); Set<Integer> handles = new HashSet<>(userProfiles.size()); diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index d725d94..1057ce3 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -30,6 +30,7 @@ import android.os.IRemoteCallback; import android.os.Looper; import android.os.MessageQueue; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Slog; import com.android.server.SystemService; @@ -37,6 +38,8 @@ import com.android.server.SystemService; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IFingerprintService; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintDaemonCallback; import android.hardware.fingerprint.IFingerprintServiceReceiver; import static android.Manifest.permission.MANAGE_FINGERPRINT; @@ -55,20 +58,19 @@ import java.util.List; * * @hide */ -public class FingerprintService extends SystemService { +public class FingerprintService extends SystemService implements IBinder.DeathRecipient { private static final String TAG = "FingerprintService"; private static final boolean DEBUG = true; + private static final String FP_DATA_DIR = "fpdata"; + private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon"; + private static final int MSG_USER_SWITCHING = 10; + private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute + private ClientMonitor mAuthClient = null; private ClientMonitor mEnrollClient = null; private ClientMonitor mRemoveClient = null; - private final AppOpsManager mAppOps; - private static final int MSG_NOTIFY = 10; - private static final int MSG_USER_SWITCHING = 11; - - private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute - // Message types. Used internally to dispatch messages to the correct callback. // Must agree with the list in fingerprint.h private static final int FINGERPRINT_ERROR = -1; @@ -83,11 +85,6 @@ public class FingerprintService extends SystemService { Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { - case MSG_NOTIFY: - FpHalMsg m = (FpHalMsg) msg.obj; - handleNotify(m.type, m.arg1, m.arg2, m.arg3); - break; - case MSG_USER_SWITCHING: handleUserSwitching(msg.arg1); break; @@ -97,10 +94,13 @@ public class FingerprintService extends SystemService { } } }; + + private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); private Context mContext; - private int mHalDeviceId; + private long mHalDeviceId; private int mFailedAttempts; - private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); + private IFingerprintDaemon mDaemon; + private final Runnable mLockoutReset = new Runnable() { @Override public void run() { @@ -112,127 +112,115 @@ public class FingerprintService extends SystemService { super(context); mContext = context; mAppOps = context.getSystemService(AppOpsManager.class); - nativeInit(Looper.getMainLooper().getQueue(), this); - } - - // TODO: Move these into separate process - // JNI methods to communicate from FingerprintService to HAL - static native int nativeEnroll(byte [] token, int groupId, int timeout); - static native long nativePreEnroll(); - static native int nativeStopEnrollment(); - static native int nativeAuthenticate(long sessionId, int groupId); - static native int nativeStopAuthentication(); - static native int nativeRemove(int fingerId, int groupId); - static native int nativeOpenHal(); - static native int nativeCloseHal(); - static native void nativeInit(MessageQueue queue, FingerprintService service); - static native long nativeGetAuthenticatorId(); - static native int nativeSetActiveGroup(int gid, byte[] storePath); - - static final class FpHalMsg { - int type; // Type of the message. One of the constants in fingerprint.h - int arg1; // optional arguments - int arg2; - int arg3; - - FpHalMsg(int type, int arg1, int arg2, int arg3) { - this.type = type; - this.arg1 = arg1; - this.arg2 = arg2; - this.arg3 = arg3; - } - } - - /** - * Called from JNI to communicate messages from fingerprint HAL. - */ - void notify(int type, int arg1, int arg2, int arg3) { - mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget(); - } - - void handleNotify(int type, int arg1, int arg2, int arg3) { - Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" - + ", mAuthClients = " + mAuthClient + ", mEnrollClient = " + mEnrollClient); + } + + @Override + public void binderDied() { + Slog.v(TAG, "fingerprintd died"); + mDaemon = null; + } + + public IFingerprintDaemon getFingerprintDaemon() { + if (mDaemon == null) { + mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD)); + if (mDaemon == null) { + Slog.w(TAG, "fingerprind service not available"); + } else { + try { + mDaemon.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + Slog.w(TAG, "caught remote exception in linkToDeath: ", e); + mDaemon = null; // try again! + } + } + } + return mDaemon; + } + + protected void dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds) { + if (fingerIds.length != groupIds.length) { + Slog.w(TAG, "fingerIds and groupIds differ in length: f[]=" + + fingerIds + ", g[]=" + groupIds); + return; + } + if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds); + // TODO: update fingerprint/name pairs + } + + protected void dispatchRemoved(long deviceId, int fingerId, int groupId) { + final ClientMonitor client = mRemoveClient; + if (fingerId != 0) { + ContentResolver res = mContext.getContentResolver(); + removeTemplateForUser(mRemoveClient, fingerId); + } + if (client != null && client.sendRemoved(fingerId, groupId)) { + removeClient(mRemoveClient); + } + } + + protected void dispatchError(long deviceId, int error) { if (mEnrollClient != null) { final IBinder token = mEnrollClient.token; - if (dispatchNotify(mEnrollClient, type, arg1, arg2, arg3)) { + if (mEnrollClient.sendError(error)) { stopEnrollment(token, false); - removeClient(mEnrollClient); } + } else if (mAuthClient != null) { + final IBinder token = mAuthClient.token; + if (mAuthClient.sendError(error)) { + stopAuthentication(token, false); + } + } else if (mRemoveClient != null) { + if (mRemoveClient.sendError(error)) removeClient(mRemoveClient); } + } + + protected void dispatchAuthenticated(long deviceId, int fingerId, int groupId) { if (mAuthClient != null) { final IBinder token = mAuthClient.token; - if (dispatchNotify(mAuthClient, type, arg1, arg2, arg3)) { + if (mAuthClient.sendAuthenticated(fingerId, groupId)) { stopAuthentication(token, false); removeClient(mAuthClient); } } - if (mRemoveClient != null) { - if (dispatchNotify(mRemoveClient, type, arg1, arg2, arg3)) { - removeClient(mRemoveClient); + } + + protected void dispatchAcquired(long deviceId, int acquiredInfo) { + if (mEnrollClient != null) { + if (mEnrollClient.sendAcquired(acquiredInfo)) { + removeClient(mEnrollClient); + } + } else if (mAuthClient != null) { + if (mAuthClient.sendAcquired(acquiredInfo)) { + removeClient(mAuthClient); } } + } void handleUserSwitching(int userId) { updateActiveGroup(userId); } - /* - * Dispatch notify events to clients. - * - * @return true if the operation is done, i.e. authentication completed - */ - boolean dispatchNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) { - boolean operationCompleted = false; - int fpId; - int groupId; - int remaining; - int acquireInfo; - switch (type) { - case FINGERPRINT_ERROR: - fpId = arg1; - operationCompleted = clientMonitor.sendError(fpId); - break; - case FINGERPRINT_ACQUIRED: - acquireInfo = arg1; - operationCompleted = clientMonitor.sendAcquired(acquireInfo); - break; - case FINGERPRINT_AUTHENTICATED: - fpId = arg1; - groupId = arg2; - operationCompleted = clientMonitor.sendAuthenticated(fpId, groupId); - break; - case FINGERPRINT_TEMPLATE_ENROLLING: - fpId = arg1; - groupId = arg2; - remaining = arg3; - operationCompleted = clientMonitor.sendEnrollResult(fpId, groupId, remaining); + protected void dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { + if (mEnrollClient != null) { + if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) { if (remaining == 0) { - addTemplateForUser(clientMonitor, fpId); - operationCompleted = true; // enroll completed - } - break; - case FINGERPRINT_TEMPLATE_REMOVED: - fpId = arg1; - groupId = arg2; - operationCompleted = clientMonitor.sendRemoved(fpId, groupId); - if (fpId != 0) { - removeTemplateForUser(clientMonitor, fpId); + ContentResolver res = mContext.getContentResolver(); + addTemplateForUser(mEnrollClient, fingerId); + removeClient(mEnrollClient); } - break; + } } - return operationCompleted; } - private void removeClient(ClientMonitor clientMonitor) { - if (clientMonitor == null) return; - clientMonitor.destroy(); - if (clientMonitor == mAuthClient) { + private void removeClient(ClientMonitor client) { + if (client == null) return; + client.destroy(); + if (client == mAuthClient) { mAuthClient = null; - } else if (clientMonitor == mEnrollClient) { + } else if (client == mEnrollClient) { mEnrollClient = null; - } else if (clientMonitor == mRemoveClient) { + } else if (client == mRemoveClient) { mRemoveClient = null; } } @@ -273,17 +261,36 @@ public class FingerprintService extends SystemService { void startEnrollment(IBinder token, byte[] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, int flags) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "enroll: no fingeprintd!"); + return; + } stopPendingOperations(); mEnrollClient = new ClientMonitor(token, receiver, groupId); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); - final int result = nativeEnroll(cryptoToken, groupId, timeout); - if (result != 0) { - Slog.w(TAG, "startEnroll failed, result=" + result); + try { + final int result = daemon.enroll(cryptoToken, groupId, timeout); + if (result != 0) { + Slog.w(TAG, "startEnroll failed, result=" + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "startEnroll failed", e); } } public long startPreEnroll(IBinder token) { - return nativePreEnroll(); + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "startPreEnroll: no fingeprintd!"); + return 0; + } + try { + return daemon.preEnroll(); + } catch (RemoteException e) { + Slog.e(TAG, "startPreEnroll failed", e); + } + return 0; } private void stopPendingOperations() { @@ -297,20 +304,34 @@ public class FingerprintService extends SystemService { } void stopEnrollment(IBinder token, boolean notify) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "stopEnrollment: no fingeprintd!"); + return; + } final ClientMonitor client = mEnrollClient; if (client == null || client.token != token) return; - int result = nativeStopEnrollment(); + try { + int result = daemon.cancelEnrollment(); + if (result != 0) { + Slog.w(TAG, "startEnrollCancel failed, result = " + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "stopEnrollment failed", e); + } if (notify) { client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mEnrollClient); - if (result != 0) { - Slog.w(TAG, "startEnrollCancel failed, result=" + result); - } } void startAuthentication(IBinder token, long opId, int groupId, IFingerprintServiceReceiver receiver, int flags) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "startAuthentication: no fingeprintd!"); + return; + } stopPendingOperations(); mAuthClient = new ClientMonitor(token, receiver, groupId); if (inLockoutMode()) { @@ -322,32 +343,54 @@ public class FingerprintService extends SystemService { return; } final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); - final int result = nativeAuthenticate(opId, groupId); - if (result != 0) { - Slog.w(TAG, "startAuthentication failed, result=" + result); + try { + final int result = daemon.authenticate(opId, groupId); + if (result != 0) { + Slog.w(TAG, "startAuthentication failed, result=" + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "startAuthentication failed", e); } } void stopAuthentication(IBinder token, boolean notify) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "stopAuthentication: no fingeprintd!"); + return; + } final ClientMonitor client = mAuthClient; if (client == null || client.token != token) return; - int result = nativeStopAuthentication(); + try { + int result = daemon.cancelAuthentication(); + if (result != 0) { + Slog.w(TAG, "stopAuthentication failed, result=" + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "stopAuthentication failed", e); + } if (notify) { client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mAuthClient); - if (result != 0) { - Slog.w(TAG, "stopAuthentication failed, result=" + result); - } } void startRemove(IBinder token, int fingerId, int userId, IFingerprintServiceReceiver receiver) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "startRemove: no fingeprintd!"); + return; + } mRemoveClient = new ClientMonitor(token, receiver, userId); // The fingerprint template ids will be removed when we get confirmation from the HAL - final int result = nativeRemove(fingerId, userId); - if (result != 0) { - Slog.w(TAG, "startRemove with id = " + fingerId + " failed with result=" + result); + try { + final int result = daemon.remove(fingerId, userId); + if (result != 0) { + Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "startRemove failed", e); } } @@ -364,7 +407,7 @@ public class FingerprintService extends SystemService { "Must have " + permission + " permission."); } - private boolean canUserFingerPrint(String opPackageName) { + private boolean canUseFingerprint(String opPackageName) { checkPermission(USE_FINGERPRINT); return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(), @@ -496,15 +539,48 @@ public class FingerprintService extends SystemService { } } - private final class FingerprintServiceWrapper extends IFingerprintService.Stub { + private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() { + + @Override + public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { + dispatchEnrollResult(deviceId, fingerId, groupId, remaining); + } + + @Override + public void onAcquired(long deviceId, int acquiredInfo) { + dispatchAcquired(deviceId, acquiredInfo); + } + + @Override + public void onAuthenticated(long deviceId, int fingerId, int groupId) { + dispatchAuthenticated(deviceId, fingerId, groupId); + } + + @Override + public void onError(long deviceId, int error) { + dispatchError(deviceId, error); + } + + @Override + public void onRemoved(long deviceId, int fingerId, int groupId) { + dispatchRemoved(deviceId, fingerId, groupId); + } + @Override + public void onEnumerate(long deviceId, int[] fingerIds, int[] groupIds) { + dispatchEnumerate(deviceId, fingerIds, groupIds); + } + + }; + + private final class FingerprintServiceWrapper extends IFingerprintService.Stub { + @Override // Binder call public long preEnroll(IBinder token) { checkPermission(MANAGE_FINGERPRINT); return startPreEnroll(token); } - @Override - // Binder call + @Override // Binder call public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, final IFingerprintServiceReceiver receiver, final int flags) { checkPermission(MANAGE_FINGERPRINT); @@ -517,8 +593,7 @@ public class FingerprintService extends SystemService { }); } - @Override - // Binder call + @Override // Binder call public void cancelEnrollment(final IBinder token) { checkPermission(MANAGE_FINGERPRINT); mHandler.post(new Runnable() { @@ -529,12 +604,11 @@ public class FingerprintService extends SystemService { }); } - @Override - // Binder call + @Override // Binder call public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) { checkPermission(USE_FINGERPRINT); - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return; } mHandler.post(new Runnable() { @@ -545,11 +619,9 @@ public class FingerprintService extends SystemService { }); } - @Override - - // Binder call + @Override // Binder call public void cancelAuthentication(final IBinder token, String opPackageName) { - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return; } mHandler.post(new Runnable() { @@ -560,8 +632,7 @@ public class FingerprintService extends SystemService { }); } - @Override - // Binder call + @Override // Binder call public void remove(final IBinder token, final int fingerId, final int groupId, final IFingerprintServiceReceiver receiver) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission @@ -574,17 +645,15 @@ public class FingerprintService extends SystemService { } - @Override - // Binder call + @Override // Binder call public boolean isHardwareDetected(long deviceId, String opPackageName) { - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return false; } - return mHalDeviceId != 0; // TODO + return mHalDeviceId != 0; } - @Override - // Binder call + @Override // Binder call public void rename(final int fingerId, final int groupId, final String name) { checkPermission(MANAGE_FINGERPRINT); mHandler.post(new Runnable() { @@ -595,69 +664,102 @@ public class FingerprintService extends SystemService { }); } - @Override - // Binder call + @Override // Binder call public List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName) { - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return Collections.emptyList(); } return FingerprintService.this.getEnrolledFingerprints(groupId); } - @Override - // Binder call + @Override // Binder call public boolean hasEnrolledFingerprints(int groupId, String opPackageName) { - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return false; } return FingerprintService.this.hasEnrolledFingerprints(groupId); } - @Override + @Override // Binder call public long getAuthenticatorId(String opPackageName) { - if (!canUserFingerPrint(opPackageName)) { + if (!canUseFingerprint(opPackageName)) { return 0; } - return nativeGetAuthenticatorId(); + return FingerprintService.this.getAuthenticatorId(); } } @Override public void onStart() { publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper()); - mHalDeviceId = nativeOpenHal(); - updateActiveGroup(ActivityManager.getCurrentUser()); + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon != null) { + try { + daemon.init(mDaemonCallback); + mHalDeviceId = daemon.openHal(); + updateActiveGroup(ActivityManager.getCurrentUser()); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to open fingeprintd HAL", e); + } + } if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId); listenForUserSwitches(); } private void updateActiveGroup(int userId) { - if (mHalDeviceId != 0) { - File path = Environment.getUserSystemDirectory(userId); - nativeSetActiveGroup(userId, path.getAbsolutePath().getBytes()); + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon != null) { + try { + // TODO: if this is a managed profile, use the profile parent's directory for + // storage. + final File systemDir = Environment.getUserSystemDirectory(userId); + final File fpDir = new File(systemDir, FP_DATA_DIR); + if (!fpDir.exists()) { + if (!fpDir.mkdir()) { + Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath()); + return; + } + } + daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes()); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to setActiveGroup():", e); + } } } private void listenForUserSwitches() { try { ActivityManagerNative.getDefault().registerUserSwitchObserver( - new IUserSwitchObserver.Stub() { - @Override - public void onUserSwitching(int newUserId, IRemoteCallback reply) { - mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */) - .sendToTarget(); - } - @Override - public void onUserSwitchComplete(int newUserId) throws RemoteException { - // Ignore. - } - @Override - public void onForegroundProfileSwitch(int newProfileId) { - // Ignore. - } - }); + new IUserSwitchObserver.Stub() { + @Override + public void onUserSwitching(int newUserId, IRemoteCallback reply) { + mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */) + .sendToTarget(); + } + @Override + public void onUserSwitchComplete(int newUserId) throws RemoteException { + // Ignore. + } + @Override + public void onForegroundProfileSwitch(int newProfileId) { + // Ignore. + } + }); } catch (RemoteException e) { Slog.w(TAG, "Failed to listen for user switching event" ,e); } } + + public long getAuthenticatorId() { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon != null) { + try { + return daemon.getAuthenticatorId(); + } catch (RemoteException e) { + Slog.e(TAG, "getAuthenticatorId failed", e); + } + } + return 0; + } + } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 74e8e4d..6a47238 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6356,12 +6356,14 @@ public class PackageManagerService extends IPackageManager.Stub { // to scan the package again. deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, false /* extract libs */); if (!TextUtils.equals(oldPrimaryCpuAbi, pkg.applicationInfo.primaryCpuAbi)) { - throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " (" + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "unexpected abi change for " + pkg.packageName + " (" + oldPrimaryCpuAbi + "-> " + pkg.applicationInfo.primaryCpuAbi); } if (!TextUtils.equals(oldSecondaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi)) { - throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " (" + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "unexpected abi change for " + pkg.packageName + " (" + oldSecondaryCpuAbi + "-> " + pkg.applicationInfo.secondaryCpuAbi); } } @@ -11661,7 +11663,7 @@ public class PackageManagerService extends IPackageManager.Stub { true /* extract libs */); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); - res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error "); + res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI"); return; } diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java index 8942325..ad662be 100644 --- a/services/core/java/com/android/server/pm/PermissionsState.java +++ b/services/core/java/com/android/server/pm/PermissionsState.java @@ -381,10 +381,10 @@ public final class PermissionsState { * * @return The gids for all device users. */ - public int[] computeGids() { + public int[] computeGids(int[] userIds) { int[] gids = mGlobalGids; - for (int userId : UserManagerService.getInstance().getUserIds()) { + for (int userId : userIds) { final int[] userGids = computeGids(userId); gids = appendInts(gids, userGids); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 76ef19f..d2a135c 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2022,83 +2022,8 @@ final class Settings { |FileUtils.S_IRGRP|FileUtils.S_IWGRP, -1, -1); - // Write package list file now, use a JournaledFile. - File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp"); - JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); - - final File writeTarget = journal.chooseForWrite(); - fstr = new FileOutputStream(writeTarget); - str = new BufferedOutputStream(fstr); - try { - FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID); - - StringBuilder sb = new StringBuilder(); - for (final PackageSetting pkg : mPackages.values()) { - if (pkg.pkg == null || pkg.pkg.applicationInfo == null) { - Slog.w(TAG, "Skipping " + pkg + " due to missing metadata"); - continue; - } - - final ApplicationInfo ai = pkg.pkg.applicationInfo; - final String dataPath = ai.dataDir; - final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - final int[] gids = pkg.getPermissionsState().computeGids(); - - // Avoid any application that has a space in its path. - if (dataPath.indexOf(" ") >= 0) - continue; - - // we store on each line the following information for now: - // - // pkgName - package name - // userId - application-specific user id - // debugFlag - 0 or 1 if the package is debuggable. - // dataPath - path to package's data path - // seinfo - seinfo label for the app (assigned at install time) - // gids - supplementary gids this app launches with - // - // NOTE: We prefer not to expose all ApplicationInfo flags for now. - // - // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS - // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: - // system/core/logd/LogStatistics.cpp - // system/core/run-as/run-as.c - // system/core/sdcard/sdcard.c - // external/libselinux/src/android.c:package_info_init() - // - sb.setLength(0); - sb.append(ai.packageName); - sb.append(" "); - sb.append((int)ai.uid); - sb.append(isDebug ? " 1 " : " 0 "); - sb.append(dataPath); - sb.append(" "); - sb.append(ai.seinfo); - sb.append(" "); - if (gids != null && gids.length > 0) { - sb.append(gids[0]); - for (int i = 1; i < gids.length; i++) { - sb.append(","); - sb.append(gids[i]); - } - } else { - sb.append("none"); - } - sb.append("\n"); - str.write(sb.toString().getBytes()); - } - str.flush(); - FileUtils.sync(fstr); - str.close(); - journal.commit(); - } catch (Exception e) { - Slog.wtf(TAG, "Failed to write packages.list", e); - IoUtils.closeQuietly(str); - journal.rollback(); - } - + writePackageListLPr(); writeAllUsersPackageRestrictionsLPr(); - writeAllRuntimePermissionsLPr(); return; @@ -2119,6 +2044,99 @@ final class Settings { //Debug.stopMethodTracing(); } + void writePackageListLPr() { + writePackageListLPr(-1); + } + + void writePackageListLPr(int creatingUserId) { + // Only derive GIDs for active users (not dying) + final List<UserInfo> users = UserManagerService.getInstance().getUsers(true); + int[] userIds = new int[users.size()]; + for (int i = 0; i < userIds.length; i++) { + userIds[i] = users.get(i).id; + } + if (creatingUserId != -1) { + userIds = ArrayUtils.appendInt(userIds, creatingUserId); + } + + // Write package list file now, use a JournaledFile. + File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp"); + JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile); + + final File writeTarget = journal.chooseForWrite(); + FileOutputStream fstr = null; + BufferedOutputStream str = null; + try { + fstr = new FileOutputStream(writeTarget); + str = new BufferedOutputStream(fstr); + FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID); + + StringBuilder sb = new StringBuilder(); + for (final PackageSetting pkg : mPackages.values()) { + if (pkg.pkg == null || pkg.pkg.applicationInfo == null) { + Slog.w(TAG, "Skipping " + pkg + " due to missing metadata"); + continue; + } + + final ApplicationInfo ai = pkg.pkg.applicationInfo; + final String dataPath = ai.dataDir; + final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final int[] gids = pkg.getPermissionsState().computeGids(userIds); + + // Avoid any application that has a space in its path. + if (dataPath.indexOf(" ") >= 0) + continue; + + // we store on each line the following information for now: + // + // pkgName - package name + // userId - application-specific user id + // debugFlag - 0 or 1 if the package is debuggable. + // dataPath - path to package's data path + // seinfo - seinfo label for the app (assigned at install time) + // gids - supplementary gids this app launches with + // + // NOTE: We prefer not to expose all ApplicationInfo flags for now. + // + // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS + // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: + // system/core/logd/LogStatistics.cpp + // system/core/run-as/run-as.c + // system/core/sdcard/sdcard.c + // external/libselinux/src/android.c:package_info_init() + // + sb.setLength(0); + sb.append(ai.packageName); + sb.append(" "); + sb.append((int)ai.uid); + sb.append(isDebug ? " 1 " : " 0 "); + sb.append(dataPath); + sb.append(" "); + sb.append(ai.seinfo); + sb.append(" "); + if (gids != null && gids.length > 0) { + sb.append(gids[0]); + for (int i = 1; i < gids.length; i++) { + sb.append(","); + sb.append(gids[i]); + } + } else { + sb.append("none"); + } + sb.append("\n"); + str.write(sb.toString().getBytes()); + } + str.flush(); + FileUtils.sync(fstr); + str.close(); + journal.commit(); + } catch (Exception e) { + Slog.wtf(TAG, "Failed to write packages.list", e); + IoUtils.closeQuietly(str); + journal.rollback(); + } + } + void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg) throws java.io.IOException { serializer.startTag(null, "updated-package"); @@ -3491,6 +3509,7 @@ final class Settings { } readDefaultPreferredAppsLPw(service, userHandle); writePackageRestrictionsLPr(userHandle); + writePackageListLPr(userHandle); } void removeUserLPw(int userId) { @@ -3506,6 +3525,8 @@ final class Settings { removeCrossProfileIntentFiltersLPw(userId); mRuntimePermissionsPersistence.onUserRemoved(userId); + + writePackageListLPr(); } void removeCrossProfileIntentFiltersLPw(int userId) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index a4e9c68..9bb5e40 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -51,7 +51,6 @@ import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; import android.media.session.MediaSessionLegacyHelper; -import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.FactoryTest; @@ -97,7 +96,6 @@ import com.android.internal.policy.PhoneWindow; import android.view.Surface; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -458,7 +456,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // menu needs to be displayed. boolean mLastFocusNeedsMenu = false; - FakeWindow mHideNavFakeWindow = null; + InputConsumer mInputConsumer = null; static final Rect mTmpParentFrame = new Rect(); static final Rect mTmpDisplayFrame = new Rect(); @@ -1817,7 +1815,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_APPLICATION_STARTING: case TYPE_BOOT_PROGRESS: case TYPE_DISPLAY_OVERLAY: - case TYPE_HIDDEN_NAV_CONSUMER: + case TYPE_INPUT_CONSUMER: case TYPE_KEYGUARD_SCRIM: case TYPE_KEYGUARD_DIALOG: case TYPE_MAGNIFICATION_OVERLAY: @@ -1942,75 +1940,75 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_VOICE_INTERACTION: // voice interaction layer is almost immediately above apps. return 5; - case TYPE_SYSTEM_DIALOG: + case TYPE_INPUT_CONSUMER: return 6; + case TYPE_SYSTEM_DIALOG: + return 7; case TYPE_TOAST: // toasts and the plugged-in battery thing - return 7; + return 8; case TYPE_PRIORITY_PHONE: // SIM errors and unlock. Not sure if this really should be in a high layer. - return 8; + return 9; case TYPE_DREAM: // used for Dreams (screensavers with TYPE_DREAM windows) - return 9; + return 10; case TYPE_SYSTEM_ALERT: // like the ANR / app crashed dialogs - return 10; + return 11; case TYPE_INPUT_METHOD: // on-screen keyboards and other such input method user interfaces go here. - return 11; + return 12; case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. - return 12; + return 13; case TYPE_KEYGUARD_SCRIM: // the safety window that shows behind keyguard while keyguard is starting - return 13; - case TYPE_STATUS_BAR_SUB_PANEL: return 14; - case TYPE_STATUS_BAR: + case TYPE_STATUS_BAR_SUB_PANEL: return 15; - case TYPE_STATUS_BAR_PANEL: + case TYPE_STATUS_BAR: return 16; - case TYPE_KEYGUARD_DIALOG: + case TYPE_STATUS_BAR_PANEL: return 17; + case TYPE_KEYGUARD_DIALOG: + return 18; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 18; + return 19; case TYPE_SYSTEM_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 19; + return 20; case TYPE_NAVIGATION_BAR: // the navigation bar, if available, shows atop most things - return 20; + return 21; case TYPE_NAVIGATION_BAR_PANEL: // some panels (e.g. search) need to show on top of the navigation bar - return 21; + return 22; case TYPE_SYSTEM_ERROR: // system-level error dialogs - return 22; + return 23; case TYPE_MAGNIFICATION_OVERLAY: // used to highlight the magnified portion of a display - return 23; + return 24; case TYPE_DISPLAY_OVERLAY: // used to simulate secondary display devices - return 24; + return 25; case TYPE_DRAG: // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - return 25; + return 26; case TYPE_ACCESSIBILITY_OVERLAY: // overlay put by accessibility services to intercept user interaction - return 26; - case TYPE_SECURE_SYSTEM_OVERLAY: return 27; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 28; + case TYPE_BOOT_PROGRESS: + return 29; case TYPE_POINTER: // the (mouse) pointer layer - return 29; - case TYPE_HIDDEN_NAV_CONSUMER: return 30; } Log.e(TAG, "Unknown window type: " + type); @@ -3385,15 +3383,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // detect when the user presses anywhere to bring back the nav // bar and ensure the application doesn't see the event. if (navVisible || navAllowedHidden) { - if (mHideNavFakeWindow != null) { - mHideNavFakeWindow.dismiss(); - mHideNavFakeWindow = null; + if (mInputConsumer != null) { + mInputConsumer.dismiss(); + mInputConsumer = null; } - } else if (mHideNavFakeWindow == null) { - mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow( - mHandler.getLooper(), mHideNavInputEventReceiverFactory, - "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0, - 0, false, false, true); + } else if (mInputConsumer == null) { + mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(), + mHideNavInputEventReceiverFactory); } // For purposes of positioning and showing the nav bar, if we have @@ -6311,7 +6307,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis); // prevent status bar interaction from clearing certain flags - boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR; + int type = win.getAttrs().type; + boolean statusBarHasFocus = type == TYPE_STATUS_BAR; if (statusBarHasFocus && !isStatusBarKeyguard()) { int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION @@ -6323,6 +6320,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } vis = (vis & ~flags) | (oldVis & flags); } + if (windowTypeToLayerLw(type) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) { + // We can't get into fullscreen from this window otherwise the consumer would not get + // the input events. + vis = (vis & ~View.SYSTEM_UI_FLAG_FULLSCREEN); + } if (!areTranslucentBarsAllowed() && transWin != mStatusBar) { vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 482ae24..66ae9ef 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -1248,7 +1248,7 @@ final class AccessibilityController { && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY && windowType != WindowManager.LayoutParams.TYPE_DRAG - && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER + && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER && windowType != WindowManager.LayoutParams.TYPE_POINTER && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY diff --git a/services/core/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 1136ced..0581a16 100644 --- a/services/core/java/com/android/server/wm/FakeWindowImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -16,17 +16,18 @@ package com.android.server.wm; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; - import android.os.Looper; import android.os.Process; import android.view.Display; import android.view.InputChannel; import android.view.InputEventReceiver; +import android.view.WindowManager; import android.view.WindowManagerPolicy; -public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputWindowHandle; + +public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer { final WindowManagerService mService; final InputChannel mServerChannel, mClientChannel; final InputApplicationHandle mApplicationHandle; @@ -34,12 +35,9 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { final InputEventReceiver mInputEventReceiver; final int mWindowLayer; - boolean mTouchFullscreen; - - public FakeWindowImpl(WindowManagerService service, - Looper looper, InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) { + public InputConsumerImpl(WindowManagerService service, Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory) { + String name = "input consumer"; mService = service; InputChannel[] channels = InputChannel.openInputChannelPair(name); @@ -58,31 +56,25 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { mWindowHandle = new InputWindowHandle(mApplicationHandle, null, Display.DEFAULT_DISPLAY); mWindowHandle.name = name; mWindowHandle.inputChannel = mServerChannel; - mWindowLayer = getLayerLw(windowType); + mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; + mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType); mWindowHandle.layer = mWindowLayer; - mWindowHandle.layoutParamsFlags = layoutParamsFlags; - mWindowHandle.layoutParamsType = windowType; + mWindowHandle.layoutParamsFlags = 0; mWindowHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; mWindowHandle.visible = true; - mWindowHandle.canReceiveKeys = canReceiveKeys; - mWindowHandle.hasFocus = hasFocus; + mWindowHandle.canReceiveKeys = false; + mWindowHandle.hasFocus = false; mWindowHandle.hasWallpaper = false; mWindowHandle.paused = false; mWindowHandle.ownerPid = Process.myPid(); mWindowHandle.ownerUid = Process.myUid(); mWindowHandle.inputFeatures = 0; mWindowHandle.scaleFactor = 1.0f; - - mTouchFullscreen = touchFullscreen; } void layout(int dw, int dh) { - if (mTouchFullscreen) { - mWindowHandle.touchableRegion.set(0, 0, dw, dh); - } else { - mWindowHandle.touchableRegion.setEmpty(); - } + mWindowHandle.touchableRegion.set(0, 0, dw, dh); mWindowHandle.frameLeft = 0; mWindowHandle.frameTop = 0; mWindowHandle.frameRight = dw; @@ -92,7 +84,7 @@ public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { @Override public void dismiss() { synchronized (mService.mWindowMap) { - if (mService.removeFakeWindowLocked(this)) { + if (mService.removeInputConsumer()) { mInputEventReceiver.dispose(); mService.mInputManager.unregisterInputChannel(mServerChannel); mClientChannel.dispose(); diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index c24fcb3..ae442e5 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,10 +16,6 @@ package com.android.server.wm; -import com.android.server.input.InputManagerService; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; - import android.app.ActivityManagerNative; import android.graphics.Rect; import android.os.RemoteException; @@ -30,17 +26,21 @@ import android.view.InputChannel; import android.view.KeyEvent; import android.view.WindowManager; +import com.android.server.input.InputApplicationHandle; +import com.android.server.input.InputManagerService; +import com.android.server.input.InputWindowHandle; + import java.util.Arrays; final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private final WindowManagerService mService; - + // Current window with input focus for keys and other non-touch events. May be null. private WindowState mInputFocus; - + // When true, prevents input dispatch from proceeding until set to false again. private boolean mInputDispatchFrozen; - + // When true, input dispatch proceeds normally. Otherwise all events are dropped. // Initially false, so that input does not get dispatched until boot is finished at // which point the ActivityManager will enable dispatching. @@ -256,10 +256,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } } - final int NFW = mService.mFakeWindows.size(); - for (int i = 0; i < NFW; i++) { - addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle); - } + boolean addInputConsumerHandle = mService.mInputConsumer != null; // Add all windows on the default display. final int numDisplays = mService.mDisplayContents.size(); @@ -273,6 +270,11 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { // Skip this window because it cannot possibly receive input. continue; } + if (addInputConsumerHandle + && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) { + addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle); + addInputConsumerHandle = false; + } final int flags = child.mAttrs.flags; final int privateFlags = child.mAttrs.privateFlags; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d956d76..cebb909 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -108,7 +108,6 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; import android.view.WindowManagerInternal; import android.view.WindowManagerPolicy; -import android.view.WindowManagerPolicy.FakeWindow; import android.view.WindowManagerPolicy.PointerEventListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -382,10 +381,10 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>(); /** - * Fake windows added to the window manager. Note: ordered from top to - * bottom, opposite of mWindows. + * The input consumer added to the window manager which consumes input events to windows below + * it. */ - final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<>(); + InputConsumerImpl mInputConsumer; /** * Windows that are being resized. Used so we can tell the client about @@ -8966,9 +8965,8 @@ public class WindowManagerService extends IWindowManager.Stub final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; - final int NFW = mFakeWindows.size(); - for (int i=0; i<NFW; i++) { - mFakeWindows.get(i).layout(dw, dh); + if (mInputConsumer != null) { + mInputConsumer.layout(dw, dh); } final int N = windows.size(); @@ -10995,28 +10993,19 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public FakeWindow addFakeWindow(Looper looper, - InputEventReceiver.Factory inputEventReceiverFactory, - String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, - boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) { + public InputConsumerImpl addInputConsumer(Looper looper, + InputEventReceiver.Factory inputEventReceiverFactory) { synchronized (mWindowMap) { - FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory, - name, windowType, layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen); - int i=0; - while (i<mFakeWindows.size()) { - if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) { - break; - } - } - mFakeWindows.add(i, fw); + mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory); mInputMonitor.updateInputWindowsLw(true); - return fw; + return mInputConsumer; } } - boolean removeFakeWindowLocked(FakeWindow window) { + boolean removeInputConsumer() { synchronized (mWindowMap) { - if (mFakeWindows.remove(window)) { + if (mInputConsumer != null) { + mInputConsumer = null; mInputMonitor.updateInputWindowsLw(true); return true; } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index a5546cf..9556b08 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -10,7 +10,6 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ - $(LOCAL_REL_DIR)/com_android_server_fingerprint_FingerprintService.cpp \ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \ diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 7db7414..67872da 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -41,7 +41,6 @@ int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_hdmi_HdmiCecController(JNIEnv* env); int register_android_server_tv_TvInputHal(JNIEnv* env); int register_android_server_PersistentDataBlockService(JNIEnv* env); -int register_android_server_fingerprint_FingerprintService(JNIEnv* env); int register_android_server_Watchdog(JNIEnv* env); }; @@ -79,7 +78,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_hdmi_HdmiCecController(env); register_android_server_tv_TvInputHal(env); register_android_server_PersistentDataBlockService(env); - register_android_server_fingerprint_FingerprintService(env); register_android_server_Watchdog(env); return JNI_VERSION_1_4; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9ad7e11..a9e76d8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6392,25 +6392,34 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public boolean setPermissionGranted(ComponentName admin, String packageName, - String permission, boolean granted) throws RemoteException { + public boolean setPermissionGrantState(ComponentName admin, String packageName, + String permission, int grantState) throws RemoteException { UserHandle user = Binder.getCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long ident = Binder.clearCallingIdentity(); try { PackageManager packageManager = mContext.getPackageManager(); - if (granted) { - packageManager.grantRuntimePermission(packageName, permission, user); - packageManager.updatePermissionFlags(permission, packageName, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); - } else { - packageManager.revokeRuntimePermission(packageName, - permission, user); - packageManager.updatePermissionFlags(permission, packageName, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, - PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); + switch (grantState) { + case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: { + packageManager.grantRuntimePermission(packageName, permission, user); + packageManager.updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); + } break; + + case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: { + packageManager.revokeRuntimePermission(packageName, + permission, user); + packageManager.updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, user); + } break; + + case DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT: { + packageManager.updatePermissionFlags(permission, packageName, + PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, user); + } break; } return true; } catch (SecurityException se) { diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index d6ff475..a615675 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -131,6 +131,11 @@ class IntervalStats { usageStats.mBeginIdleTime = timeStamp; } + void updateLastUsedTime(String packageName, long lastUsedTime) { + UsageStats usageStats = getOrCreateUsageStats(packageName); + usageStats.mLastTimeUsed = lastUsedTime; + } + void updateConfigurationStats(Configuration config, long timeStamp) { if (activeConfiguration != null) { ConfigurationStats activeStats = configurations.get(activeConfiguration); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index f7bcf2a..ff3bb28 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -99,7 +99,9 @@ public class UsageStatsService extends SystemService implements private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds. static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4 - : 1L * 24 * 60 * ONE_MINUTE; // 1 day + : 12 * 60 * ONE_MINUTE; // 12 hours of screen-on time sans dream-time + static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 8 + : 2L * 24 * 60 * ONE_MINUTE; // 2 days static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE : 8 * 60 * ONE_MINUTE; // 8 hours static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10 @@ -356,7 +358,7 @@ public class UsageStatsService extends SystemService implements final int packageCount = packages.size(); for (int p = 0; p < packageCount; p++) { final String packageName = packages.get(p).packageName; - final boolean isIdle = isAppIdleFiltered(packageName, userId); + final boolean isIdle = isAppIdleFiltered(packageName, userId, timeNow); mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, isIdle ? 1 : 0, packageName)); mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow); @@ -386,7 +388,8 @@ public class UsageStatsService extends SystemService implements void updateDisplayLocked() { boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState() - != Display.STATE_OFF; + == Display.STATE_ON; + if (screenOn == mScreenOn) return; mScreenOn = screenOn; @@ -533,14 +536,16 @@ public class UsageStatsService extends SystemService implements void reportEvent(UsageEvents.Event event, int userId) { synchronized (mLock) { final long timeNow = checkAndGetTimeLocked(); + final long screenOnTime = getScreenOnTimeLocked(timeNow); convertToSystemTimeLocked(event); final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - final long lastUsed = service.getBeginIdleTime(event.mPackage); - final long screenOnTime = getScreenOnTimeLocked(timeNow); - final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, screenOnTime); - service.reportEvent(event, screenOnTime); + final long beginIdleTime = service.getBeginIdleTime(event.mPackage); + final long lastUsedTime = service.getLastUsedTime(event.mPackage); + final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime, + lastUsedTime, screenOnTime, timeNow); + service.reportEvent(event, getScreenOnTimeLocked(timeNow)); // Inform listeners if necessary if ((event.mEventType == Event.MOVE_TO_FOREGROUND || event.mEventType == Event.MOVE_TO_BACKGROUND @@ -556,8 +561,9 @@ public class UsageStatsService extends SystemService implements } /** - * Forces the app's beginIdleTime to reflect idle or active. If idle, then it rolls back the - * beginIdleTime to a point in time thats behind the threshold for idle. + * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle, + * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind + * the threshold for idle. */ void forceIdleState(String packageName, int userId, boolean idle) { synchronized (mLock) { @@ -567,10 +573,13 @@ public class UsageStatsService extends SystemService implements final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); - final long lastUsed = service.getBeginIdleTime(packageName); - final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, - getScreenOnTimeLocked(timeNow)); + final long beginIdleTime = service.getBeginIdleTime(packageName); + final long lastUsedTime = service.getLastUsedTime(packageName); + final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime, + lastUsedTime, screenOnTime, timeNow); service.setBeginIdleTime(packageName, deviceUsageTime); + service.setLastUsedTime(packageName, + timeNow - (idle ? DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS : 0) - 5000); // Inform listeners if necessary if (previouslyIdle != idle) { // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage); @@ -650,13 +659,14 @@ public class UsageStatsService extends SystemService implements } } - private boolean isAppIdleUnfiltered(String packageName, int userId) { + private boolean isAppIdleUnfiltered(String packageName, int userId, long timeNow) { synchronized (mLock) { - final long timeNow = checkAndGetTimeLocked(); + final long screenOnTime = getScreenOnTimeLocked(timeNow); final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow); long beginIdleTime = service.getBeginIdleTime(packageName); - return hasPassedIdleTimeout(beginIdleTime, getScreenOnTimeLocked(timeNow)); + long lastUsedTime = service.getLastUsedTime(packageName); + return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow); } } @@ -665,8 +675,10 @@ public class UsageStatsService extends SystemService implements * @param currentTime current time in device usage timebase * @return whether it's been used far enough in the past to be considered inactive */ - boolean hasPassedIdleTimeout(long timestamp, long currentTime) { - return timestamp <= currentTime - mAppIdleDurationMillis; + boolean hasPassedIdleTimeoutLocked(long beginIdleTime, long lastUsedTime, + long screenOnTime, long currentTime) { + return (beginIdleTime <= screenOnTime - mAppIdleDurationMillis) + && (lastUsedTime <= currentTime - DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS); } void addListener(AppIdleStateChangeListener listener) { @@ -689,9 +701,12 @@ public class UsageStatsService extends SystemService implements * This happens if the device is plugged in or temporarily allowed to make exceptions. * Called by interface impls. */ - boolean isAppIdleFiltered(String packageName, int userId) { + boolean isAppIdleFiltered(String packageName, int userId, long timeNow) { if (packageName == null) return false; synchronized (mLock) { + if (timeNow == -1) { + timeNow = checkAndGetTimeLocked(); + } // Temporary exemption, probably due to device charging or occasional allowance to // be allowed to sync, etc. if (mAppIdleParoled) { @@ -715,7 +730,7 @@ public class UsageStatsService extends SystemService implements return false; } - return isAppIdleUnfiltered(packageName, userId); + return isAppIdleUnfiltered(packageName, userId, timeNow); } void setAppIdle(String packageName, boolean idle, int userId) { @@ -948,7 +963,7 @@ public class UsageStatsService extends SystemService implements } final long token = Binder.clearCallingIdentity(); try { - return UsageStatsService.this.isAppIdleFiltered(packageName, userId); + return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1); } finally { Binder.restoreCallingIdentity(token); } @@ -1053,7 +1068,7 @@ public class UsageStatsService extends SystemService implements @Override public boolean isAppIdle(String packageName, int userId) { - return UsageStatsService.this.isAppIdleFiltered(packageName, userId); + return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1); } @Override diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index b7e1c22..7c00dae 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -216,12 +216,19 @@ class UserUsageStatsService { } /** - * Sets the last timestamp for each of the intervals. - * @param lastTimestamp + * Sets the beginIdleTime for each of the intervals. + * @param beginIdleTime */ - void setBeginIdleTime(String packageName, long deviceUsageTime) { + void setBeginIdleTime(String packageName, long beginIdleTime) { for (IntervalStats stats : mCurrentStats) { - stats.updateBeginIdleTime(packageName, deviceUsageTime); + stats.updateBeginIdleTime(packageName, beginIdleTime); + } + notifyStatsChanged(); + } + + void setLastUsedTime(String packageName, long lastUsedTime) { + for (IntervalStats stats : mCurrentStats) { + stats.updateLastUsedTime(packageName, lastUsedTime); } notifyStatsChanged(); } @@ -390,6 +397,16 @@ class UserUsageStatsService { } } + long getLastUsedTime(String packageName) { + final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]; + UsageStats packageUsage; + if ((packageUsage = yearly.packageStats.get(packageName)) == null) { + return -1; + } else { + return packageUsage.getLastTimeUsed(); + } + } + void persistActiveStats() { if (mStatsChanged) { Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk"); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index fcdb6d6..35bdceb 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -151,7 +151,7 @@ public class VoiceInteractionManagerService extends SystemService { // the user to have the default voice interaction service enabled. // Note that we don't do this for low-RAM devices, since we aren't // supporting voice interaction services there. - curInteractorInfo = findAvailInteractor(userHandle, curRecognizer); + curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName()); if (curInteractorInfo != null) { // Looks good! We'll apply this one. To make it happen, we clear the // recognizer so that we don't think we have anything set and will @@ -162,6 +162,18 @@ public class VoiceInteractionManagerService extends SystemService { } } + // If forceInteractorPackage exists, try to apply the interactor from this package if + // possible and ignore the regular interactor setting. + String forceInteractorPackage = + getForceVoiceInteractionServicePackage(mContext.getResources()); + if (forceInteractorPackage != null) { + curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage); + if (curInteractorInfo != null) { + // We'll apply this one. Clear the recognizer and re-apply the settings. + curRecognizer = null; + } + } + // If we are on a svelte device, make sure an interactor is not currently // enabled; if it is, turn it off. if (!mEnableService && curInteractorStr != null) { @@ -225,8 +237,14 @@ public class VoiceInteractionManagerService extends SystemService { private boolean shouldEnableService(Resources res) { // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag. - return !ActivityManager.isLowRamDeviceStatic() - || res.getBoolean(com.android.internal.R.bool.config_forceEnableVoiceInteractionService); + return !ActivityManager.isLowRamDeviceStatic() || + getForceVoiceInteractionServicePackage(res) != null; + } + + private String getForceVoiceInteractionServicePackage(Resources res) { + String interactorPackage = + res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage); + return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage; } public void systemRunning(boolean safeMode) { @@ -279,7 +297,7 @@ public class VoiceInteractionManagerService extends SystemService { } } - VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) { + VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) { List<ResolveInfo> available = mContext.getPackageManager().queryIntentServicesAsUser( new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle); @@ -300,8 +318,8 @@ public class VoiceInteractionManagerService extends SystemService { VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( mContext.getPackageManager(), comp, userHandle); if (info.getParseError() == null) { - if (recognizer == null || info.getServiceInfo().packageName.equals( - recognizer.getPackageName())) { + if (packageName == null || info.getServiceInfo().packageName.equals( + packageName)) { if (foundInfo == null) { foundInfo = info; } else { diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs index 42b1cf1..0c177ef 100644 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs @@ -116,7 +116,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -124,7 +123,6 @@ static void renderAllMeshes() { } static void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; @@ -196,7 +194,6 @@ int root(void) { uint32_t w = rsAllocationGetDimX(gOffscreen); uint32_t h = rsAllocationGetDimY(gOffscreen); - uint32_t numElements = w*h; rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET); diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs index 05ef3ac..13a3c85 100644 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs @@ -115,7 +115,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -123,7 +122,6 @@ static void renderAllMeshes() { } static void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs index de2a0a7..d3dd5b9 100644 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs +++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs @@ -123,7 +123,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -131,7 +130,6 @@ static void renderAllMeshes() { } void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; @@ -163,7 +161,7 @@ int root(void) { rsMatrixMultiply(&matrix, &gPostureMatrix); rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - + rsgProgramVertexLoadModelMatrix(&matrix); renderAllMeshes(); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs index 27e5b11..43cf4e0 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs @@ -85,7 +85,7 @@ static void runSubTest(int index) { TestData testData; fillSurfaceParams(&testData); - rs_allocation null_alloc; + rs_allocation null_alloc = {0}; rsForEach(gTestScripts[index].testScript, gTestScripts[index].testData, null_alloc, @@ -125,7 +125,6 @@ static bool checkInit() { static int benchMode = 0; static bool benchmarkSingleTest = false; -static int benchSubMode = 0; static int runningLoops = 0; static bool sendMsgFlag = false; @@ -209,7 +208,6 @@ static void benchmark() { drawOffscreenResult(0, 0, quadW, quadH); int left = 0, right = 0, top = 0, bottom = 0; - uint width = rsgGetWidth(); uint height = rsgGetHeight(); rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); rsgBindFont(gFontSerif); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs index 7f10019..0f50828 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs @@ -52,7 +52,6 @@ static void displayFontSamples(int fillNum) { fonts[3] = gFontSerif; fonts[4] = gFontSans; - uint width = gRenderSurfaceW; uint height = gRenderSurfaceH; int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(sampleText, &left, &right, &top, &bottom); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs index 5089092..e87db39 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs @@ -143,7 +143,6 @@ static void createParticle(Particle_t *part, int idx, float scale) { float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); float id = d / gGalaxyRadius; float z = randomGauss() * 0.4f * (1.0f - id); - float p = -d * ELLIPSE_TWIST; if (d < gGalaxyRadius * 0.33f) { part->color.x = (uchar) (220 + id * 35); @@ -305,7 +304,6 @@ static void drawMeshInPage(float xStart, float yStart, int wResolution, int hRes int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); float textHeight = (float)(top - bottom); - float textWidth = (float)(right - left); rs_matrix4x4 matrix; rsMatrixLoadScale(&matrix, size, size, 1.0); diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh index 575794b..00793c0 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh @@ -19,7 +19,7 @@ #include "scenegraph_objects.rsh" //#define DEBUG_PARAMS -static void debugParam(SgShaderParam *p, SgShaderParamData *pData) { +static inline void debugParam(SgShaderParam *p, SgShaderParamData *pData) { rsDebug("____________ Param ____________", p); printName(pData->paramName); rsDebug("bufferOffset", p->bufferOffset); @@ -44,8 +44,7 @@ static void debugParam(SgShaderParam *p, SgShaderParamData *pData) { } } - -static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { +static inline void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { #ifdef DEBUG_PARAMS rsDebug("Writing value ", *input); rsDebug("Writing vec size ", vecSize); @@ -67,7 +66,7 @@ static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { } } -static bool processParam(SgShaderParam *p, SgShaderParamData *pData, +static inline bool processParam(SgShaderParam *p, SgShaderParamData *pData, uint8_t *constantBuffer, const SgCamera *currentCam, SgFragmentShader *shader) { @@ -155,7 +154,7 @@ static bool processParam(SgShaderParam *p, SgShaderParamData *pData, return true; } -static void processAllParams(rs_allocation shaderConst, +static inline void processAllParams(rs_allocation shaderConst, rs_allocation allParams, const SgCamera *camera) { if (rsIsObject(shaderConst)) { @@ -177,7 +176,7 @@ static void processAllParams(rs_allocation shaderConst, } } -static void processTextureParams(SgFragmentShader *shader) { +static inline void processTextureParams(SgFragmentShader *shader) { int numParams = 0; if (rsIsObject(shader->shaderTextureParams)) { numParams = rsAllocationGetDimX(shader->shaderTextureParams); diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs index 8a73dbd..205b2cb 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs @@ -78,7 +78,7 @@ static void draw(SgRenderable *obj) { if (rsIsObject(renderState->pr)) { rsgBindProgramRaster(renderState->pr); } else { - rs_program_raster pr; + rs_program_raster pr = {0}; rsgBindProgramRaster(pr); } diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh index bdca3ab..90ae212 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh @@ -208,7 +208,7 @@ typedef struct Texture_s { rs_allocation texture; } SgTexture; -static void printName(rs_allocation name) { +static inline void printName(rs_allocation name) { if (!rsIsObject(name)) { rsDebug("no name", 0); return; @@ -217,7 +217,7 @@ static void printName(rs_allocation name) { rsDebug((const char*)rsGetElementAt(name, 0), 0); } -static void printCameraInfo(const SgCamera *cam) { +static inline void printCameraInfo(const SgCamera *cam) { rsDebug("***** Camera information. ptr:", cam); printName(cam->name); const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); @@ -233,7 +233,7 @@ static void printCameraInfo(const SgCamera *cam) { rsDebug("View: ", &cam->view); } -static void printLightInfo(const SgLight *light) { +static inline void printLightInfo(const SgLight *light) { rsDebug("***** Light information. ptr:", light); printName(light->name); const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); @@ -246,7 +246,7 @@ static void printLightInfo(const SgLight *light) { rsDebug("Type: ", light->type); } -static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { +static inline void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { rsDebug("=================================", screenX); rsDebug("Point X", screenX); rsDebug("Point Y", screenY); @@ -290,7 +290,7 @@ static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 * *pnt = cam->position.xyz; } -static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { +static inline bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { // Solving for t^2 + Bt + C = 0 float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz; float B = dot(originMinusCenter, vec) * 2.0f; diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs index 941b5a8..1d0b5be 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs @@ -26,6 +26,7 @@ typedef struct { } ParentData; //#define DEBUG_TRANSFORMS +/* Unused function: static void debugTransform(SgTransform *data, const ParentData *parent) { rsDebug("****** <Transform> ******", (int)data); printName(data->name); @@ -53,6 +54,7 @@ static void debugTransform(SgTransform *data, const ParentData *parent) { rsDebug("timestamp", data->timestamp); rsDebug("****** </Transform> ******", (int)data); } +*/ static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { rs_matrix4x4 temp; @@ -119,7 +121,7 @@ void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) } if (rsIsObject(data->children)) { - rs_allocation nullAlloc; + rs_allocation nullAlloc = {0}; rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild)); } diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs index 997a1a7..d94da52 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs @@ -41,9 +41,7 @@ void init() { gRotate = 0.0f; } -static int pos = 50; static float gRotateY = 120.0f; -static float3 gLookAt = 0; static float gZoom = 50.0f; static void displayLoading() { if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) { diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs index ae32e3a..735f6b9 100644 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs +++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs @@ -131,7 +131,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java index 2c2c672..fdb6e75 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java @@ -169,7 +169,7 @@ public final class BridgeResources extends Resources { } @Override - public int getColor(int id) throws NotFoundException { + public int getColor(int id, Theme theme) throws NotFoundException { Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag); if (value != null) { @@ -192,22 +192,21 @@ public final class BridgeResources extends Resources { } } - // id was not found or not resolved. Throw a NotFoundException. - throwException(id); - - // this is not used since the method above always throws - return 0; + // Suppress possible NPE. getColorStateList will never return null, it will instead + // throw an exception, but intelliJ can't figure that out + //noinspection ConstantConditions + return getColorStateList(id, theme).getDefaultColor(); } @Override - public ColorStateList getColorStateList(int id) throws NotFoundException { + public ColorStateList getColorStateList(int id, Theme theme) throws NotFoundException { Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag); if (resValue != null) { ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(), mContext); if (stateList != null) { - return stateList; + return stateList.obtainForTheme(theme); } } diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index 771cf57..54a508a 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -320,7 +320,8 @@ public final class BridgeTypedArray extends TypedArray { BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( parser, mContext, resValue.isFramework()); try { - return ColorStateList.createFromXml(mContext.getResources(), blockParser); + return ColorStateList.createFromXml(mContext.getResources(), blockParser, + mContext.getTheme()); } finally { blockParser.ensurePopped(); } diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java index dda8ebb..4226526 100644 --- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java +++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java @@ -82,36 +82,8 @@ public class StaticLayout_Delegate { builder.mText = text; builder.mWidths = new float[length]; - - // compute all possible breakpoints. - BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale)); - it.setText(new Segment(builder.mText, 0, length)); - - // average word length in english is 5. So, initialize the possible breaks with a guess. - List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d)); - int loc; - it.first(); - while ((loc = it.next()) != BreakIterator.DONE) { - breaks.add(loc); - } - LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth); - TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop); - List<Primitive> primitives = - computePrimitives(builder.mText, builder.mWidths, length, breaks); - BreakStrategy strategy = BreakStrategy.getStrategy(breakStrategy); - switch (strategy) { - case GREEDY: - builder.mLineBreaker = - new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator); - break; - case HIGH_QUALITY: - // TODO -// break; - case BALANCED: - builder.mLineBreaker = new OptimizingLineBreaker(primitives, lineWidth, - tabStopCalculator); - break; - } + builder.mLineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth); + builder.mTabStopCalculator = new TabStops(variableTabStops, defaultTabStop); } @LayoutlibDelegate @@ -160,6 +132,37 @@ public class StaticLayout_Delegate { if (builder == null) { return 0; } + + // compute all possible breakpoints. + int length = builder.mWidths.length; + BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale)); + it.setText(new Segment(builder.mText, 0, length)); + + // average word length in english is 5. So, initialize the possible breaks with a guess. + List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d)); + int loc; + it.first(); + while ((loc = it.next()) != BreakIterator.DONE) { + breaks.add(loc); + } + + List<Primitive> primitives = + computePrimitives(builder.mText, builder.mWidths, length, breaks); + switch (builder.mBreakStrategy) { + case Layout.BREAK_STRATEGY_SIMPLE: + builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth, + builder.mTabStopCalculator); + break; + case Layout.BREAK_STRATEGY_HIGH_QUALITY: + // TODO +// break; + case Layout.BREAK_STRATEGY_BALANCED: + builder.mLineBreaker = new OptimizingLineBreaker(primitives, builder.mLineWidth, + builder.mTabStopCalculator); + break; + default: + throw new AssertionError("Unknown break strategy: " + builder.mBreakStrategy); + } builder.mLineBreaker.computeBreaks(recycle); return recycle.breaks.length; } @@ -223,22 +226,8 @@ public class StaticLayout_Delegate { float[] mWidths; LineBreaker mLineBreaker; long mNativeHyphenator; - } - - private enum BreakStrategy { - GREEDY, HIGH_QUALITY, BALANCED; - - static BreakStrategy getStrategy(int strategy) { - switch (strategy) { - case 0: - return GREEDY; - case 1: - return HIGH_QUALITY; - case 2: - return BALANCED; - default: - throw new AssertionError("Unknown break strategy: " + strategy); - } - } + int mBreakStrategy; + LineWidth mLineWidth; + TabStops mTabStopCalculator; } } diff --git a/tools/layoutlib/bridge/src/android/view/View_Delegate.java b/tools/layoutlib/bridge/src/android/view/View_Delegate.java index 8215f7c..408ec54 100644 --- a/tools/layoutlib/bridge/src/android/view/View_Delegate.java +++ b/tools/layoutlib/bridge/src/android/view/View_Delegate.java @@ -16,8 +16,12 @@ package android.view; +import com.android.layoutlib.bridge.android.BridgeContext; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import android.content.Context; +import android.os.IBinder; + /** * Delegate used to provide new implementation of a select few methods of {@link View} * @@ -31,4 +35,13 @@ public class View_Delegate { /*package*/ static boolean isInEditMode(View thisView) { return true; } + + @LayoutlibDelegate + /*package*/ static IBinder getWindowToken(View thisView) { + Context baseContext = BridgeContext.getBaseContext(thisView.getContext()); + if (baseContext instanceof BridgeContext) { + return ((BridgeContext) baseContext).getBinder(); + } + return null; + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 59f07a7..eded804 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -65,8 +65,11 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.IInterface; import android.os.Looper; +import android.os.Parcel; import android.os.PowerManager; +import android.os.RemoteException; import android.os.UserHandle; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -82,6 +85,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.textservice.TextServicesManager; import java.io.File; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -139,6 +143,7 @@ public final class BridgeContext extends Context { private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>(); private SharedPreferences mSharedPreferences; private ClassLoader mClassLoader; + private IBinder mBinder; /** * @param projectKey An Object identifying the project. This is used for the cache mechanism. @@ -708,44 +713,48 @@ public final class BridgeContext extends Context { } } } else if (defStyleRes != 0) { - boolean isFrameworkRes = true; - Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); - if (value == null) { - value = mLayoutlibCallback.resolveResourceId(defStyleRes); - isFrameworkRes = false; - } + StyleResourceValue item = mDynamicIdToStyleMap.get(defStyleRes); + if (item != null) { + defStyleValues = item; + } else { + boolean isFrameworkRes = true; + Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes); + if (value == null) { + value = mLayoutlibCallback.resolveResourceId(defStyleRes); + isFrameworkRes = false; + } - if (value != null) { - if ((value.getFirst() == ResourceType.STYLE)) { - // look for the style in all resources: - StyleResourceValue item = mRenderResources.getStyle(value.getSecond(), - isFrameworkRes); - if (item != null) { - if (defaultPropMap != null) { - defaultPropMap.put("style", item.getName()); + if (value != null) { + if ((value.getFirst() == ResourceType.STYLE)) { + // look for the style in all resources: + item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes); + if (item != null) { + if (defaultPropMap != null) { + defaultPropMap.put("style", item.getName()); + } + + defStyleValues = item; + } else { + Bridge.getLog().error(null, + String.format( + "Style with id 0x%x (resolved to '%s') does not exist.", + defStyleRes, value.getSecond()), + null); } - - defStyleValues = item; } else { Bridge.getLog().error(null, String.format( - "Style with id 0x%x (resolved to '%s') does not exist.", - defStyleRes, value.getSecond()), + "Resource id 0x%x is not of type STYLE (instead %s)", + defStyleRes, value.getFirst().toString()), null); } } else { Bridge.getLog().error(null, String.format( - "Resource id 0x%x is not of type STYLE (instead %s)", - defStyleRes, value.getFirst().toString()), + "Failed to find style with id 0x%x in current theme", + defStyleRes), null); } - } else { - Bridge.getLog().error(null, - String.format( - "Failed to find style with id 0x%x in current theme", - defStyleRes), - null); } } @@ -996,6 +1005,61 @@ public final class BridgeContext extends Context { return context; } + public IBinder getBinder() { + if (mBinder == null) { + // create a dummy binder. We only need it be not null. + mBinder = new IBinder() { + @Override + public String getInterfaceDescriptor() throws RemoteException { + return null; + } + + @Override + public boolean pingBinder() { + return false; + } + + @Override + public boolean isBinderAlive() { + return false; + } + + @Override + public IInterface queryLocalInterface(String descriptor) { + return null; + } + + @Override + public void dump(FileDescriptor fd, String[] args) throws RemoteException { + + } + + @Override + public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { + + } + + @Override + public boolean transact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + return false; + } + + @Override + public void linkToDeath(DeathRecipient recipient, int flags) + throws RemoteException { + + } + + @Override + public boolean unlinkToDeath(DeathRecipient recipient, int flags) { + return false; + } + }; + } + return mBinder; + } + //------------ NOT OVERRIDEN -------------------- @Override diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index 91be0bd..63115e4 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -124,9 +124,14 @@ public class Main { if (platformDir != null) { return platformDir; } - // Test if workingDir is platform/frameworks/base/tools/layoutlib. That is, root should be - // workingDir/../../../../ (4 levels up) + + // Test if workingDir is platform/frameworks/base/tools/layoutlib/bridge. File currentDir = workingDir; + if (currentDir.getName().equalsIgnoreCase("bridge")) { + currentDir = currentDir.getParentFile(); + } + // Test if currentDir is platform/frameworks/base/tools/layoutlib. That is, root should be + // workingDir/../../../../ (4 levels up) for (int i = 0; i < 4; i++) { if (currentDir != null) { currentDir = currentDir.getParentFile(); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index 3aa7cdf..f6c2626 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -24,9 +24,11 @@ import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -86,7 +88,23 @@ public class AsmGenerator { public AsmGenerator(Log log, String osDestJar, ICreateInfo createInfo) { mLog = log; mOsDestJar = osDestJar; - mInjectClasses = createInfo.getInjectedClasses(); + ArrayList<Class<?>> injectedClasses = + new ArrayList<Class<?>>(Arrays.asList(createInfo.getInjectedClasses())); + // Search for and add anonymous inner classes also. + ListIterator<Class<?>> iter = injectedClasses.listIterator(); + while (iter.hasNext()) { + Class<?> clazz = iter.next(); + try { + int i = 1; + while(i < 100) { + iter.add(Class.forName(clazz.getName() + "$" + i)); + i++; + } + } catch (ClassNotFoundException ignored) { + // Expected. + } + } + mInjectClasses = injectedClasses.toArray(new Class<?>[0]); mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods())); // Create the map/set of methods to change to delegates @@ -290,13 +308,7 @@ public class AsmGenerator { * e.g. it returns something like "com/foo/OuterClass$InnerClass1$InnerClass2.class" */ private String classToEntryPath(Class<?> clazz) { - String name = ""; - Class<?> parent; - while ((parent = clazz.getEnclosingClass()) != null) { - name = "$" + clazz.getSimpleName() + name; - clazz = parent; - } - return classNameToEntryPath(clazz.getCanonicalName() + name); + return classNameToEntryPath(clazz.getName()); } /** diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index deb94c4..499bea4 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -136,6 +136,8 @@ public final class CreateInfo implements ICreateInfo { ICreateInfo.class, CreateInfo.class, LayoutlibDelegate.class, + InjectMethodRunnable.class, + InjectMethodRunnables.class, /* Java package classes */ AutoCloseable.class, Objects.class, @@ -172,6 +174,7 @@ public final class CreateInfo implements ICreateInfo { "android.view.Display#getWindowManager", "android.view.LayoutInflater#rInflate", "android.view.LayoutInflater#parseInclude", + "android.view.View#getWindowToken", "android.view.View#isInEditMode", "android.view.ViewRootImpl#isInTouchMode", "android.view.WindowManagerGlobal#getWindowManagerService", @@ -302,4 +305,3 @@ public final class CreateInfo implements ICreateInfo { InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER); }}; } - diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java index ac10639..54b1fe6 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java @@ -85,6 +85,12 @@ public interface ICreateInfo { Map<String, InjectMethodRunnable> getInjectedMethodsMap(); abstract class InjectMethodRunnable { - public abstract void generateMethods(ClassVisitor cv); + /** + * @param cv Must be {@link ClassVisitor}. However, the param type is object so that when + * loading the class, ClassVisitor is not loaded. This is because when injecting + * CreateInfo in LayoutLib (see {@link #getInjectedClasses()}, we don't want to inject + * asm classes also, but still keep CreateInfo loadable. + */ + public abstract void generateMethods(Object cv); } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java index 39d46d7..37fc096 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java @@ -30,7 +30,9 @@ public class InjectMethodRunnables { public static final ICreateInfo.InjectMethodRunnable CONTEXT_GET_FRAMEWORK_CLASS_LOADER = new InjectMethodRunnable() { @Override - public void generateMethods(ClassVisitor cv) { + public void generateMethods(Object classVisitor) { + assert classVisitor instanceof ClassVisitor; + ClassVisitor cv = (ClassVisitor) classVisitor; // generated by compiling the class: // class foo { public ClassLoader getFrameworkClassLoader() { return getClass().getClassLoader(); } } // and then running ASMifier on it: |
