diff options
Diffstat (limited to 'core/java/android')
51 files changed, 1022 insertions, 268 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index a9eaf29..3f1845a 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -16,6 +16,7 @@ package android.accessibilityservice; +import android.annotation.NonNull; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -27,6 +28,7 @@ import android.util.Log; import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.view.WindowManagerImpl; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; @@ -618,6 +620,23 @@ public abstract class AccessibilityService extends Service { } } + @Override + public Object getSystemService(@ServiceName @NonNull String name) { + if (getBaseContext() == null) { + throw new IllegalStateException( + "System services not available to Activities before onCreate()"); + } + + // Guarantee that we always return the same window manager instance. + if (WINDOW_SERVICE.equals(name)) { + if (mWindowManager == null) { + mWindowManager = (WindowManager) getBaseContext().getSystemService(name); + } + return mWindowManager; + } + return super.getSystemService(name); + } + /** * Implement to return the implementation of the internal accessibility * service interface. @@ -645,8 +664,10 @@ public abstract class AccessibilityService extends Service { mConnectionId = connectionId; mWindowToken = windowToken; - // Let the window manager know about our shiny new token. - WindowManagerGlobal.getInstance().setDefaultToken(mWindowToken); + // The client may have already obtained the window manager, so + // update the default token on whatever manager we gave them. + final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE); + wm.setDefaultToken(windowToken); } @Override diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 148527f..fab88a2 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5620,6 +5620,16 @@ public class Activity extends ContextThemeWrapper } /** + * @hide + */ + public void dispatchEnterAnimationComplete() { + onEnterAnimationComplete(); + if (getWindow() != null && getWindow().getDecorView() != null) { + getWindow().getDecorView().getViewTreeObserver().dispatchOnEnterAnimationComplete(); + } + } + + /** * Adjust the current immersive mode setting. * * Note that changing this value will have no effect on the activity's diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 2a17fa6..d56dc1e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -23,8 +23,8 @@ package android.app; */ public abstract class ActivityManagerInternal { // Called by the power manager. - public abstract void goingToSleep(); - public abstract void wakingUp(); + public abstract void onWakefulnessChanged(int wakefulness); + public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs, String processName, String abiOverride, int uid, Runnable crashHandler); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 98a096c..b64e724 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2536,7 +2536,7 @@ public final class ActivityThread { private void handleEnterAnimationComplete(IBinder token) { ActivityClientRecord r = mActivities.get(token); if (r != null) { - r.activity.onEnterAnimationComplete(); + r.activity.dispatchEnterAnimationComplete(); } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1de9b47..2df35df 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -20,9 +20,9 @@ import android.app.usage.IUsageStatsManager; import android.app.usage.UsageStatsManager; import android.appwidget.AppWidgetManager; import android.os.Build; - import android.service.persistentdata.IPersistentDataBlockService; import android.service.persistentdata.PersistentDataBlockManager; + import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.policy.PolicyManager; import com.android.internal.util.Preconditions; @@ -125,6 +125,7 @@ import android.print.PrintManager; import android.service.fingerprint.IFingerprintService; import android.service.fingerprint.FingerprintManager; import android.telecom.TelecomManager; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.content.ClipboardManager; import android.util.AndroidRuntimeException; @@ -561,6 +562,11 @@ class ContextImpl extends Context { return new TelephonyManager(ctx.getOuterContext()); }}); + registerService(TELEPHONY_SUBSCRIPTION_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + return new SubscriptionManager(ctx.getOuterContext()); + }}); + registerService(TELECOM_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new TelecomManager(ctx.getOuterContext()); diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 5038df9..ddd21e6 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -225,28 +225,28 @@ public class KeyguardManager { } /** - * Return whether unlocking the device is currently not requiring a password - * because of a trust agent. + * Returns whether the device is currently locked and requires a PIN, pattern or + * password to unlock. * - * @return true if the keyguard can currently be unlocked without entering credentials - * because the device is in a trusted environment. + * @return true if unlocking the device currently requires a PIN, pattern or + * password. */ - public boolean isKeyguardInTrustedState() { - return isKeyguardInTrustedState(UserHandle.getCallingUserId()); + public boolean isDeviceLocked() { + return isDeviceLocked(UserHandle.getCallingUserId()); } /** - * Return whether unlocking the device is currently not requiring a password - * because of a trust agent. + * Returns whether the device is currently locked and requires a PIN, pattern or + * password to unlock. * - * @param userId the user for which the trusted state should be reported. - * @return true if the keyguard can currently be unlocked without entering credentials - * because the device is in a trusted environment. + * @param userId the user for which the locked state should be reported. + * @return true if unlocking the device currently requires a PIN, pattern or + * password. * @hide */ - public boolean isKeyguardInTrustedState(int userId) { + public boolean isDeviceLocked(int userId) { try { - return mTrustManager.isTrusted(userId); + return mTrustManager.isDeviceLocked(userId); } catch (RemoteException e) { return false; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index aa98e97..ece2a33 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -632,55 +632,60 @@ public final class LoadedApk { public void removeContextRegistrations(Context context, String who, String what) { final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); - ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = - mReceivers.remove(context); - if (rmap != null) { - for (int i=0; i<rmap.size(); i++) { - LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); - IntentReceiverLeaked leak = new IntentReceiverLeaked( - what + " " + who + " has leaked IntentReceiver " - + rd.getIntentReceiver() + " that was " + - "originally registered here. Are you missing a " + - "call to unregisterReceiver()?"); - leak.setStackTrace(rd.getLocation().getStackTrace()); - Slog.e(ActivityThread.TAG, leak.getMessage(), leak); - if (reportRegistrationLeaks) { - StrictMode.onIntentReceiverLeaked(leak); - } - try { - ActivityManagerNative.getDefault().unregisterReceiver( - rd.getIIntentReceiver()); - } catch (RemoteException e) { - // system crashed, nothing we can do + synchronized (mReceivers) { + ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap = + mReceivers.remove(context); + if (rmap != null) { + for (int i = 0; i < rmap.size(); i++) { + LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i); + IntentReceiverLeaked leak = new IntentReceiverLeaked( + what + " " + who + " has leaked IntentReceiver " + + rd.getIntentReceiver() + " that was " + + "originally registered here. Are you missing a " + + "call to unregisterReceiver()?"); + leak.setStackTrace(rd.getLocation().getStackTrace()); + Slog.e(ActivityThread.TAG, leak.getMessage(), leak); + if (reportRegistrationLeaks) { + StrictMode.onIntentReceiverLeaked(leak); + } + try { + ActivityManagerNative.getDefault().unregisterReceiver( + rd.getIIntentReceiver()); + } catch (RemoteException e) { + // system crashed, nothing we can do + } } } + mUnregisteredReceivers.remove(context); } - mUnregisteredReceivers.remove(context); - //Slog.i(TAG, "Receiver registrations: " + mReceivers); - ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = - mServices.remove(context); - if (smap != null) { - for (int i=0; i<smap.size(); i++) { - LoadedApk.ServiceDispatcher sd = smap.valueAt(i); - ServiceConnectionLeaked leak = new ServiceConnectionLeaked( - what + " " + who + " has leaked ServiceConnection " - + sd.getServiceConnection() + " that was originally bound here"); - leak.setStackTrace(sd.getLocation().getStackTrace()); - Slog.e(ActivityThread.TAG, leak.getMessage(), leak); - if (reportRegistrationLeaks) { - StrictMode.onServiceConnectionLeaked(leak); - } - try { - ActivityManagerNative.getDefault().unbindService( - sd.getIServiceConnection()); - } catch (RemoteException e) { - // system crashed, nothing we can do + + synchronized (mServices) { + //Slog.i(TAG, "Receiver registrations: " + mReceivers); + ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = + mServices.remove(context); + if (smap != null) { + for (int i = 0; i < smap.size(); i++) { + LoadedApk.ServiceDispatcher sd = smap.valueAt(i); + ServiceConnectionLeaked leak = new ServiceConnectionLeaked( + what + " " + who + " has leaked ServiceConnection " + + sd.getServiceConnection() + " that was originally bound here"); + leak.setStackTrace(sd.getLocation().getStackTrace()); + Slog.e(ActivityThread.TAG, leak.getMessage(), leak); + if (reportRegistrationLeaks) { + StrictMode.onServiceConnectionLeaked(leak); + } + try { + ActivityManagerNative.getDefault().unbindService( + sd.getIServiceConnection()); + } catch (RemoteException e) { + // system crashed, nothing we can do + } + sd.doForget(); } - sd.doForget(); } + mUnboundServices.remove(context); + //Slog.i(TAG, "Service registrations: " + mServices); } - mUnboundServices.remove(context); - //Slog.i(TAG, "Service registrations: " + mServices); } public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 07e8dc5..9e8a793 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4115,9 +4115,9 @@ public class Notification implements Parcelable * <pre class="prettyprint"> * Notification noti = new Notification.Builder() * .setSmallIcon(R.drawable.ic_stat_player) - * .setContentTitle("Track title") // these three lines are optional - * .setContentText("Artist - Album") // if you use - * .setLargeIcon(albumArtBitmap)) // setMediaSession(token) + * .setContentTitle("Track title") + * .setContentText("Artist - Album") + * .setLargeIcon(albumArtBitmap)) * .setStyle(<b>new Notification.MediaStyle()</b> * .setMediaSession(mySession)) * .build(); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 57d53aa..d00cbb7 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1345,6 +1345,24 @@ public class DevicePolicyManager { } /** + * Returns the profile with the smallest maximum failed passwords for wipe, + * for the given user. So for primary user, it might return the primary or + * a managed profile. For a secondary user, it would be the same as the + * user passed in. + * @hide Used only by Keyguard + */ + public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) { + if (mService != null) { + try { + return mService.getProfileWithMinimumFailedPasswordsForWipe(userHandle); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return UserHandle.USER_NULL; + } + + /** * Flag for {@link #resetPassword}: don't allow other admins to change * the password again until the user has entered it. */ @@ -1363,13 +1381,16 @@ public class DevicePolicyManager { * characters when the requested quality is only numeric), in which case * the currently active quality will be increased to match. * + * <p>Calling with a null or empty password will clear any existing PIN, + * pattern or password if the current password constraints allow it. + * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * * <p>Calling this from a managed profile will throw a security exception. * - * @param password The new password for the user. + * @param password The new password for the user. Null or empty clears the password. * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}. * @return Returns true if the password was applied, or false if it is * not acceptable for the current constraints. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 07aa800..d144ae8 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -66,6 +66,7 @@ interface IDevicePolicyManager { boolean isActivePasswordSufficient(int userHandle); int getCurrentFailedPasswordAttempts(int userHandle); + int getProfileWithMinimumFailedPasswordsForWipe(int userHandle); void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, int userHandle); int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle); diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index 0a2d4f5..41ad936 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -303,4 +303,11 @@ interface IBackupManager { * {@code false} otherwise. */ void setBackupServiceActive(int whichUser, boolean makeActive); + + /** + * Queries the activity status of backup service as set by {@link #setBackupServiceActive}. + * @param whichUser User handle of the defined user whose backup active state + * is being queried. + */ + boolean isBackupServiceActive(int whichUser); } diff --git a/core/java/android/app/backup/RecentsBackupHelper.java b/core/java/android/app/backup/RecentsBackupHelper.java new file mode 100644 index 0000000..fd69d20 --- /dev/null +++ b/core/java/android/app/backup/RecentsBackupHelper.java @@ -0,0 +1,114 @@ +package android.app.backup; + +import android.content.Context; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.util.Slog; + +import java.io.File; + +/** + * Helper for saving/restoring 'recent tasks' infrastructure. + * @hide + */ +public class RecentsBackupHelper implements BackupHelper { + private static final String TAG = "RecentsBackup"; + private static final boolean DEBUG = false; + + // This must match TaskPersister.TASKS_DIRNAME, but that class is not accessible from here + private static final String RECENTS_TASK_DIR = "recent_tasks"; + + // Must match TaskPersister.IMAGES_DIRNAME, as above + private static final String RECENTS_IMAGE_DIR = "recent_images"; + + // At restore time, tasks/thumbnails are placed in these directories alongside + // the "live" recents dirs named above. + private static final String RECENTS_TASK_RESTORE_DIR = "restored_" + RECENTS_TASK_DIR; + private static final String RECENTS_IMAGE_RESTORE_DIR = "restored_" + RECENTS_IMAGE_DIR; + + // Prefixes for tagging the two kinds of recents backup records that we might generate + private static final String RECENTS_TASK_KEY = "task:"; + private static final String RECENTS_IMAGE_KEY = "image:"; + + FileBackupHelperBase mTaskFileHelper; + + final File mSystemDir; + final File mTasksDir; + final File mRestoredTasksDir; + final File mRestoredImagesDir; + final String[] mRecentFiles; + final String[] mRecentKeys; + + /** + * @param context The agent context in which this helper instance will run + */ + public RecentsBackupHelper(Context context) { + mTaskFileHelper = new FileBackupHelperBase(context); + + mSystemDir = new File(Environment.getDataDirectory(), "system"); + mTasksDir = new File(mSystemDir, RECENTS_TASK_DIR); + mRestoredTasksDir = new File(mSystemDir, RECENTS_TASK_RESTORE_DIR); + mRestoredImagesDir = new File(mSystemDir, RECENTS_IMAGE_RESTORE_DIR); + + // Currently we back up only the recent-task descriptions, not the thumbnails + File[] recentFiles = mTasksDir.listFiles(); + if (recentFiles != null) { + // We explicitly proceed even if this is a zero-size array + final int N = recentFiles.length; + mRecentKeys = new String[N]; + mRecentFiles = new String[N]; + if (DEBUG) { + Slog.i(TAG, "Identifying recents for backup: " + N); + } + for (int i = 0; i < N; i++) { + mRecentKeys[i] = new String(RECENTS_TASK_KEY + recentFiles[i].getName()); + mRecentFiles[i] = recentFiles[i].getAbsolutePath(); + if (DEBUG) { + Slog.i(TAG, " " + mRecentKeys[i]); + } + } + } else { + mRecentFiles = mRecentKeys = new String[0]; + } + } + + /** + * Task-file key: RECENTS_TASK_KEY + leaf filename + * Thumbnail-file key: RECENTS_IMAGE_KEY + leaf filename + */ + @Override + public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) { + FileBackupHelperBase.performBackup_checked(oldState, data, newState, + mRecentFiles, mRecentKeys); + } + + @Override + public void restoreEntity(BackupDataInputStream data) { + final String key = data.getKey(); + File output = null; + if (key.startsWith(RECENTS_TASK_KEY)) { + String name = key.substring(RECENTS_TASK_KEY.length()); + output = new File(mRestoredTasksDir, name); + mRestoredTasksDir.mkdirs(); + } else if (key.startsWith(RECENTS_IMAGE_KEY)) { + String name = key.substring(RECENTS_IMAGE_KEY.length()); + output = new File(mRestoredImagesDir, name); + mRestoredImagesDir.mkdirs(); + } + + if (output != null) { + if (DEBUG) { + Slog.i(TAG, "Restoring key='" + + key + "' to " + output.getAbsolutePath()); + } + mTaskFileHelper.writeFile(output, data); + } + } + + @Override + public void writeNewStateDescription(ParcelFileDescriptor newState) { + mTaskFileHelper.writeNewStateDescription(newState); + } + +} diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl index 0193711..68ea0aa 100644 --- a/core/java/android/app/trust/ITrustManager.aidl +++ b/core/java/android/app/trust/ITrustManager.aidl @@ -29,5 +29,6 @@ interface ITrustManager { void reportRequireCredentialEntry(int userId); void registerTrustListener(in ITrustListener trustListener); void unregisterTrustListener(in ITrustListener trustListener); - boolean isTrusted(int userId); + void reportKeyguardShowingChanged(); + boolean isDeviceLocked(int userId); } diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 3d262b1..705a144 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -88,6 +88,19 @@ public class TrustManager { } /** + * Reports that the visibility of the keyguard has changed. + * + * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. + */ + public void reportKeyguardShowingChanged() { + try { + mService.reportKeyguardShowingChanged(); + } catch (RemoteException e) { + onError(e); + } + } + + /** * Registers a listener for trust events. * * Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index a73ba74..0daa8e2 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2245,6 +2245,8 @@ public abstract class Context { * @see android.media.MediaRouter * @see #TELEPHONY_SERVICE * @see android.telephony.TelephonyManager + * @see #TELEPHONY_SUBSCRIPTION_SERVICE + * @see android.telephony.SubscriptionManager * @see #INPUT_METHOD_SERVICE * @see android.view.inputmethod.InputMethodManager * @see #UI_MODE_SERVICE @@ -2589,6 +2591,16 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a + * {@link android.telephony.SubscriptionManager} for handling management the + * telephony subscriptions of the device. + * + * @see #getSystemService + * @see android.telephony.SubscriptionManager + */ + public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service"; + + /** + * Use with {@link #getSystemService} to retrieve a * {@link android.telecom.TelecomManager} to manage telecom-related features * of the device. * diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a13a2ea..de7fbab 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4010,6 +4010,20 @@ public class Intent implements Parcelable, Cloneable { */ public static final int URI_ANDROID_APP_SCHEME = 1<<1; + /** + * Flag for use with {@link #toUri} and {@link #parseUri}: allow parsing + * of unsafe information. In particular, the flags {@link #FLAG_GRANT_READ_URI_PERMISSION}, + * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, {@link #FLAG_GRANT_PERSISTABLE_URI_PERMISSION}, + * and {@link #FLAG_GRANT_PREFIX_URI_PERMISSION} flags can not be set, so that the + * generated Intent can not cause unexpected data access to happen. + * + * <p>If you do not trust the source of the URI being parsed, you should still do further + * processing to protect yourself from it. In particular, when using it to start an + * activity you should usually add in {@link #CATEGORY_BROWSABLE} to limit the activities + * that can handle it.</p> + */ + public static final int URI_ALLOW_UNSAFE = 1<<2; + // --------------------------------------------------------------------- private String mAction; @@ -4309,7 +4323,7 @@ public class Intent implements Parcelable, Cloneable { // old format Intent URI } else if (!uri.startsWith("#Intent;", i)) { if (!androidApp) { - return getIntentOld(uri); + return getIntentOld(uri, flags); } else { i = -1; } @@ -4359,6 +4373,9 @@ public class Intent implements Parcelable, Cloneable { // launch flags else if (uri.startsWith("launchFlags=", i)) { intent.mFlags = Integer.decode(value).intValue(); + if ((flags& URI_ALLOW_UNSAFE) == 0) { + intent.mFlags &= ~IMMUTABLE_FLAGS; + } } // package @@ -4488,6 +4505,10 @@ public class Intent implements Parcelable, Cloneable { } public static Intent getIntentOld(String uri) throws URISyntaxException { + return getIntentOld(uri, 0); + } + + private static Intent getIntentOld(String uri, int flags) throws URISyntaxException { Intent intent; int i = uri.lastIndexOf('#'); @@ -4536,6 +4557,9 @@ public class Intent implements Parcelable, Cloneable { i += 12; int j = uri.indexOf(')', i); intent.mFlags = Integer.decode(uri.substring(i, j)).intValue(); + if ((flags& URI_ALLOW_UNSAFE) == 0) { + intent.mFlags &= ~IMMUTABLE_FLAGS; + } i = j + 1; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e9f7c50..5c705e6 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1078,6 +1078,26 @@ public abstract class PackageManager { "android.hardware.camera.capability.raw"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: At least one + * of the cameras on the device supports the + * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE} + * capability level. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_CAPABILITY_BURST_CAPTURE = + "android.hardware.camera.capability.burst_capture"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: At least one + * of the cameras on the device supports the + * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS} + * capability level. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_CAPABILITY_READ_SENSOR_SETTINGS = + "android.hardware.camera.capability.read_sensor_settings"; + + /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device is capable of communicating with * consumer IR devices. diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 754f270..98096dc 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -395,6 +395,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p><b>Range of valid values:</b><br></p> * <p><code>Min.exposure compensation * {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} <= -2 EV</code></p> * <p><code>Max.exposure compensation * {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} >= 2 EV</code></p> + * <p>LEGACY devices may support a smaller range than this, including the range [0,0], which + * indicates that changing the exposure compensation is not supported.</p> * <p>This key is available on all devices.</p> * * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 271fc30..895ae04 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -490,12 +490,16 @@ public abstract class CameraMetadata<TKey> { * <p>More specifically, this means that a size matching the * camera device's active array size is listed as a * supported size for the YUV_420_888 format in - * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}, and the - * minimum frame duration for that format and size is <= - * 1/20 s.</p> + * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}, the minimum frame + * duration for that format and size is <= 1/20 s, and + * the {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges} entry + * lists at least one FPS range where the minimum FPS + * is >= 1 / minimumFrameDuration for the maximum-size + * YUV_420_888 format.</p> * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is * guaranted to have a value between 0 and 4, inclusive.</p> * + * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP * @see CameraCharacteristics#SYNC_MAX_LATENCY * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1c9f4c6..19eca29 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1921,45 +1921,6 @@ public class ConnectivityManager { } /** - * get the information about a specific network link - * @hide - */ - public LinkQualityInfo getLinkQualityInfo(int networkType) { - try { - LinkQualityInfo li = mService.getLinkQualityInfo(networkType); - return li; - } catch (RemoteException e) { - return null; - } - } - - /** - * get the information of currently active network link - * @hide - */ - public LinkQualityInfo getActiveLinkQualityInfo() { - try { - LinkQualityInfo li = mService.getActiveLinkQualityInfo(); - return li; - } catch (RemoteException e) { - return null; - } - } - - /** - * get the information of all network links - * @hide - */ - public LinkQualityInfo[] getAllLinkQualityInfo() { - try { - LinkQualityInfo[] li = mService.getAllLinkQualityInfo(); - return li; - } catch (RemoteException e) { - return null; - } - } - - /** * Set sign in error notification to visible or in visible * * @param visible @@ -2381,15 +2342,14 @@ public class ConnectivityManager { * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. */ - public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; + public static final String EXTRA_NETWORK = "android.net.extra.NETWORK"; /** * The lookup key for a {@link NetworkRequest} object included with the intent after * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. */ - public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST = - "networkRequestNetworkRequest"; + public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST"; /** @@ -2405,8 +2365,8 @@ public class ConnectivityManager { * <receiver> tag in an AndroidManifest.xml file * <p> * The operation Intent is delivered with two extras, a {@link Network} typed - * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkRequest} - * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_REQUEST} containing + * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest} + * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing * the original requests parameters. It is important to create a new, * {@link NetworkCallback} based request before completing the processing of the * Intent to reserve the network or it will be released shortly after the Intent diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index d965f27..f45737a 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -18,11 +18,14 @@ package android.net; import android.content.Context; import android.net.IEthernetManager; +import android.net.IEthernetServiceListener; import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; +import android.os.Handler; +import android.os.Message; import android.os.RemoteException; +import java.util.ArrayList; + /** * A class representing the IP configuration of the Ethernet network. * @@ -30,9 +33,41 @@ import android.os.RemoteException; */ public class EthernetManager { private static final String TAG = "EthernetManager"; + private static final int MSG_AVAILABILITY_CHANGED = 1000; private final Context mContext; private final IEthernetManager mService; + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_AVAILABILITY_CHANGED) { + boolean isAvailable = (msg.arg1 == 1); + for (Listener listener : mListeners) { + listener.onAvailabilityChanged(isAvailable); + } + } + } + }; + private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); + private final IEthernetServiceListener.Stub mServiceListener = + new IEthernetServiceListener.Stub() { + @Override + public void onAvailabilityChanged(boolean isAvailable) { + mHandler.obtainMessage( + MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget(); + } + }; + + /** + * A listener interface to receive notification on changes in Ethernet. + */ + public interface Listener { + /** + * Called when Ethernet port's availability is changed. + * @param isAvailable {@code true} if one or more Ethernet port exists. + */ + public void onAvailabilityChanged(boolean isAvailable); + } /** * Create a new EthernetManager instance. @@ -50,12 +85,9 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { - if (mService == null) { - return new IpConfiguration(); - } try { return mService.getConfiguration(); - } catch (RemoteException e) { + } catch (NullPointerException | RemoteException e) { return new IpConfiguration(); } } @@ -64,12 +96,57 @@ public class EthernetManager { * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { - if (mService == null) { - return; - } try { mService.setConfiguration(config); - } catch (RemoteException e) { + } catch (NullPointerException | RemoteException e) { + } + } + + /** + * Indicates whether the system currently has one or more + * Ethernet interfaces. + */ + public boolean isAvailable() { + try { + return mService.isAvailable(); + } catch (NullPointerException | RemoteException e) { + return false; + } + } + + /** + * Adds a listener. + * @param listener A {@link Listener} to add. + * @throws IllegalArgumentException If the listener is null. + */ + public void addListener(Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + mListeners.add(listener); + if (mListeners.size() == 1) { + try { + mService.addListener(mServiceListener); + } catch (NullPointerException | RemoteException e) { + } + } + } + + /** + * Removes a listener. + * @param listener A {@link Listener} to remove. + * @throws IllegalArgumentException If the listener is null. + */ + public void removeListener(Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + mListeners.remove(listener); + if (mListeners.isEmpty()) { + try { + mService.removeListener(mServiceListener); + } catch (NullPointerException | RemoteException e) { + } } } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index a7bbc53..79f920e 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -17,7 +17,6 @@ package android.net; import android.app.PendingIntent; -import android.net.LinkQualityInfo; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -133,12 +132,6 @@ interface IConnectivityManager String getMobileRedirectedProvisioningUrl(); - LinkQualityInfo getLinkQualityInfo(int networkType); - - LinkQualityInfo getActiveLinkQualityInfo(); - - LinkQualityInfo[] getAllLinkQualityInfo(); - void setProvisioningNotificationVisible(boolean visible, int networkType, in String action); void setAirplaneMode(boolean enable); @@ -170,4 +163,5 @@ interface IConnectivityManager boolean addVpnAddress(String address, int prefixLength); boolean removeVpnAddress(String address, int prefixLength); + boolean setUnderlyingNetworksForVpn(in Network[] networks); } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 3fa08f8..7a92eb9 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.IpConfiguration; +import android.net.IEthernetServiceListener; /** * Interface that answers queries about, and allows changing @@ -27,4 +28,7 @@ interface IEthernetManager { IpConfiguration getConfiguration(); void setConfiguration(in IpConfiguration config); + boolean isAvailable(); + void addListener(in IEthernetServiceListener listener); + void removeListener(in IEthernetServiceListener listener); } diff --git a/core/java/android/net/IEthernetServiceListener.aidl b/core/java/android/net/IEthernetServiceListener.aidl new file mode 100644 index 0000000..356690e --- /dev/null +++ b/core/java/android/net/IEthernetServiceListener.aidl @@ -0,0 +1,23 @@ +/* + * 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.net; + +/** @hide */ +oneway interface IEthernetServiceListener +{ + void onAvailabilityChanged(boolean isAvailable); +} diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 36dd2fdfb..d36707e 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -34,7 +34,7 @@ import java.util.Objects; * * @hide */ -public class NetworkIdentity { +public class NetworkIdentity implements Comparable<NetworkIdentity> { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. @@ -76,7 +76,7 @@ public class NetworkIdentity { @Override public String toString() { - final StringBuilder builder = new StringBuilder("["); + final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); if (COMBINE_SUBTYPE_ENABLED) { @@ -95,7 +95,7 @@ public class NetworkIdentity { if (mRoaming) { builder.append(", ROAMING"); } - return builder.append("]").toString(); + return builder.append("}").toString(); } public int getType() { @@ -170,4 +170,22 @@ public class NetworkIdentity { return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); } + + @Override + public int compareTo(NetworkIdentity another) { + int res = Integer.compare(mType, another.mType); + if (res == 0) { + res = Integer.compare(mSubType, another.mSubType); + } + if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) { + res = mSubscriberId.compareTo(another.mSubscriberId); + } + if (res == 0 && mNetworkId != null && another.mNetworkId != null) { + res = mNetworkId.compareTo(another.mNetworkId); + } + if (res == 0) { + res = Boolean.compare(mRoaming, another.mRoaming); + } + return res; + } } diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 2e0e9e4..d26c70d 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -29,20 +29,23 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; + public final Network network; /** Currently only used by testing. */ public final String subscriberId; public final String networkId; public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities) { - this(networkInfo, linkProperties, networkCapabilities, null, null); + NetworkCapabilities networkCapabilities, Network network) { + this(networkInfo, linkProperties, networkCapabilities, network, null, null); } public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, String subscriberId, String networkId) { + NetworkCapabilities networkCapabilities, Network network, String subscriberId, + String networkId) { this.networkInfo = networkInfo; this.linkProperties = linkProperties; this.networkCapabilities = networkCapabilities; + this.network = network; this.subscriberId = subscriberId; this.networkId = networkId; } @@ -51,6 +54,7 @@ public class NetworkState implements Parcelable { networkInfo = in.readParcelable(null); linkProperties = in.readParcelable(null); networkCapabilities = in.readParcelable(null); + network = in.readParcelable(null); subscriberId = in.readString(); networkId = in.readString(); } @@ -65,6 +69,7 @@ public class NetworkState implements Parcelable { out.writeParcelable(networkInfo, flags); out.writeParcelable(linkProperties, flags); out.writeParcelable(networkCapabilities, flags); + out.writeParcelable(network, flags); out.writeString(subscriberId); out.writeString(networkId); } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ea5dfd1..2afe578 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -733,6 +733,22 @@ public class NetworkStats implements Parcelable { } /** + * Return text description of {@link #set} value. + */ + public static String setToCheckinString(int set) { + switch (set) { + case SET_ALL: + return "all"; + case SET_DEFAULT: + return "def"; + case SET_FOREGROUND: + return "fg"; + default: + return "unk"; + } + } + + /** * Return text description of {@link #tag} value. */ public static String tagToString(int tag) { diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 62d8738..4a4accb 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -26,6 +26,7 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; @@ -38,6 +39,7 @@ import java.io.CharArrayWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.io.PrintWriter; import java.net.ProtocolException; import java.util.Arrays; import java.util.Random; @@ -573,8 +575,22 @@ public class NetworkStatsHistory implements Parcelable { return (long) (start + (r.nextFloat() * (end - start))); } + /** + * Quickly determine if this history intersects with given window. + */ + public boolean intersects(long start, long end) { + final long dataStart = getStart(); + final long dataEnd = getEnd(); + if (start >= dataStart && start <= dataEnd) return true; + if (end >= dataStart && end <= dataEnd) return true; + if (dataStart >= start && dataStart <= end) return true; + if (dataEnd >= start && dataEnd <= end) return true; + return false; + } + public void dump(IndentingPrintWriter pw, boolean fullHistory) { - pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); + pw.print("NetworkStatsHistory: bucketDuration="); + pw.println(bucketDuration / SECOND_IN_MILLIS); pw.increaseIndent(); final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); @@ -583,19 +599,35 @@ public class NetworkStatsHistory implements Parcelable { } for (int i = start; i < bucketCount; i++) { - pw.print("bucketStart="); pw.print(bucketStart[i]); - if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); } - if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); } - if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); } - if (txBytes != null) { pw.print(" txBytes="); pw.print(txBytes[i]); } - if (txPackets != null) { pw.print(" txPackets="); pw.print(txPackets[i]); } - if (operations != null) { pw.print(" operations="); pw.print(operations[i]); } + pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS); + if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); } + if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); } + if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); } + if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); } + if (operations != null) { pw.print(" op="); pw.print(operations[i]); } pw.println(); } pw.decreaseIndent(); } + public void dumpCheckin(PrintWriter pw) { + pw.print("d,"); + pw.print(bucketDuration / SECOND_IN_MILLIS); + pw.println(); + + for (int i = 0; i < bucketCount; i++) { + pw.print("b,"); + pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(','); + if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(','); + if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(','); + if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(','); + if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(','); + if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); } + pw.println(); + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 27197cc..b839e0a 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -16,6 +16,7 @@ package android.net; +import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; @@ -34,10 +35,10 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; -import java.util.Objects; - import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * Template definition used to generically match {@link NetworkIdentity}, * usually when collecting statistics. @@ -53,6 +54,7 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_ETHERNET = 5; public static final int MATCH_MOBILE_WILDCARD = 6; public static final int MATCH_WIFI_WILDCARD = 7; + public static final int MATCH_BLUETOOTH = 8; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -134,6 +136,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_ETHERNET, null, null); } + /** + * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style + * networks together. + */ + public static NetworkTemplate buildTemplateBluetooth() { + return new NetworkTemplate(MATCH_BLUETOOTH, null, null); + } + private final int mMatchRule; private final String mSubscriberId; private final String mNetworkId; @@ -222,6 +232,8 @@ public class NetworkTemplate implements Parcelable { return matchesMobileWildcard(ident); case MATCH_WIFI_WILDCARD: return matchesWifiWildcard(ident); + case MATCH_BLUETOOTH: + return matchesBluetooth(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -316,6 +328,16 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Check if matches Bluetooth network template. + */ + private boolean matchesBluetooth(NetworkIdentity ident) { + if (ident.mType == TYPE_BLUETOOTH) { + return true; + } + return false; + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -332,6 +354,8 @@ public class NetworkTemplate implements Parcelable { return "MOBILE_WILDCARD"; case MATCH_WIFI_WILDCARD: return "WIFI_WILDCARD"; + case MATCH_BLUETOOTH: + return "BLUETOOTH"; default: return "UNKNOWN"; } diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index d469487..ad54912 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.net.Network; import android.net.NetworkUtils; import android.os.Binder; import android.os.IBinder; @@ -288,6 +289,46 @@ public class VpnService extends Service { } /** + * Sets the underlying networks used by the VPN for its upstream connections. + * + * Used by the system to know the actual networks that carry traffic for apps affected by this + * VPN in order to present this information to the user (e.g., via status bar icons). + * + * This method only needs to be called if the VPN has explicitly bound its underlying + * communications channels — such as the socket(s) passed to {@link #protect(int)} — + * to a {@code Network} using APIs such as {@link Network#bindSocket} or {@link + * Network#bindDatagramSocket}. The VPN should call this method every time the set of {@code + * Network}s it is using changes. + * + * {@code networks} is one of the following: + * <ul> + * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in + * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular) + * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear + * first in the array.</li> + * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no + * underlying network connection, and thus, app traffic will not be sent or received.</li> + * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's + * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket} + * APIs mentioned above to send traffic over specific channels. + * </ul> + * + * This call will succeed only if the VPN is currently established. For setting this value when + * the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}. + * + * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. + * + * @return {@code true} on success. + */ + public boolean setUnderlyingNetworks(Network[] networks) { + try { + return getService().setUnderlyingNetworksForVpn(networks); + } catch (RemoteException e) { + throw new IllegalStateException(e); + } + } + + /** * Return the communication interface to the service. This method returns * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE} * action. Applications overriding this method must identify the intent @@ -663,6 +704,20 @@ public class VpnService extends Service { } /** + * Sets the underlying networks used by the VPN for its upstream connections. + * + * @see VpnService#setUnderlyingNetworks + * + * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. + * + * @return this {@link Builder} object to facilitate chaining method calls. + */ + public Builder setUnderlyingNetworks(Network[] networks) { + mConfig.underlyingNetworks = networks != null ? networks.clone() : null; + return this; + } + + /** * Create a VPN interface using the parameters supplied to this * builder. The interface works on IP packets, and a file descriptor * is returned for the application to access them. Each read diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 9d78360..6f31768 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -25,6 +25,58 @@ import android.view.Display; */ public abstract class PowerManagerInternal { /** + * Wakefulness: The device is asleep. It can only be awoken by a call to wakeUp(). + * The screen should be off or in the process of being turned off by the display controller. + * The device typically passes through the dozing state first. + */ + public static final int WAKEFULNESS_ASLEEP = 0; + + /** + * Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). + * When the user activity timeout expires, the device may start dreaming or go to sleep. + */ + public static final int WAKEFULNESS_AWAKE = 1; + + /** + * Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), + * which ends the dream. The device goes to sleep when goToSleep() is called, when + * the dream ends or when unplugged. + * User activity may brighten the screen but does not end the dream. + */ + public static final int WAKEFULNESS_DREAMING = 2; + + /** + * Wakefulness: The device is dozing. It is almost asleep but is allowing a special + * low-power "doze" dream to run which keeps the display on but lets the application + * processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. + * The device fully goes to sleep if the dream cannot be started or ends on its own. + */ + public static final int WAKEFULNESS_DOZING = 3; + + public static String wakefulnessToString(int wakefulness) { + switch (wakefulness) { + case WAKEFULNESS_ASLEEP: + return "Asleep"; + case WAKEFULNESS_AWAKE: + return "Awake"; + case WAKEFULNESS_DREAMING: + return "Dreaming"; + case WAKEFULNESS_DOZING: + return "Dozing"; + default: + return Integer.toString(wakefulness); + } + } + + /** + * Returns true if the wakefulness state represents an interactive state + * as defined by {@link android.os.PowerManager#isInteractive}. + */ + public static boolean isInteractive(int wakefulness) { + return wakefulness == WAKEFULNESS_AWAKE || wakefulness == WAKEFULNESS_DREAMING; + } + + /** * Used by the window manager to override the screen brightness based on the * current foreground activity. * diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 3ec45e9..f023df7 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -387,7 +387,6 @@ public class CallLog { public static Uri addCall(CallerInfo ci, Context context, String number, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage) { - // FIXME using -1 as subId instead of SubscriptionManager.INVALID_SUB_ID return addCall(ci, context, number, presentation, callType, features, accountHandle, start, duration, dataUsage, false); } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 36401eb..ce28d0a 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -474,13 +474,14 @@ public class ZenModeConfig implements Parcelable { return downtime; } - public static Condition toTimeCondition(Context context, int minutesFromNow) { + public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) { final long now = System.currentTimeMillis(); final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS; - return toTimeCondition(context, now + millis, minutesFromNow, now); + return toTimeCondition(context, now + millis, minutesFromNow, now, userHandle); } - public static Condition toTimeCondition(Context context, long time, int minutes, long now) { + public static Condition toTimeCondition(Context context, long time, int minutes, long now, + int userHandle) { final int num, summaryResId, line1ResId; if (minutes < 60) { // display as minutes @@ -493,7 +494,7 @@ public class ZenModeConfig implements Parcelable { summaryResId = com.android.internal.R.plurals.zen_mode_duration_hours_summary; line1ResId = com.android.internal.R.plurals.zen_mode_duration_hours; } - final String skeleton = DateFormat.is24HourFormat(context) ? "Hm" : "hma"; + final String skeleton = DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma"; final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); final CharSequence formattedTime = DateFormat.format(pattern, time); final Resources res = context.getResources(); diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl index bb0c2b2..f07d0d0 100644 --- a/core/java/android/service/trust/ITrustAgentService.aidl +++ b/core/java/android/service/trust/ITrustAgentService.aidl @@ -25,6 +25,8 @@ import android.service.trust.ITrustAgentServiceCallback; interface ITrustAgentService { oneway void onUnlockAttempt(boolean successful); oneway void onTrustTimeout(); + oneway void onDeviceLocked(); + oneway void onDeviceUnlocked(); oneway void onConfigure(in List<PersistableBundle> options, IBinder token); oneway void setCallback(ITrustAgentServiceCallback callback); } diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java index d6c997f..62fa978 100644 --- a/core/java/android/service/trust/TrustAgentService.java +++ b/core/java/android/service/trust/TrustAgentService.java @@ -92,6 +92,8 @@ public class TrustAgentService extends Service { private static final int MSG_UNLOCK_ATTEMPT = 1; private static final int MSG_CONFIGURE = 2; private static final int MSG_TRUST_TIMEOUT = 3; + private static final int MSG_DEVICE_LOCKED = 4; + private static final int MSG_DEVICE_UNLOCKED = 5; /** * Class containing raw data for a given configuration request. @@ -134,6 +136,12 @@ public class TrustAgentService extends Service { case MSG_TRUST_TIMEOUT: onTrustTimeout(); break; + case MSG_DEVICE_LOCKED: + onDeviceLocked(); + break; + case MSG_DEVICE_UNLOCKED: + onDeviceUnlocked(); + break; } } }; @@ -173,6 +181,20 @@ public class TrustAgentService extends Service { public void onTrustTimeout() { } + /** + * Called when the device enters a state where a PIN, pattern or + * password must be entered to unlock it. + */ + public void onDeviceLocked() { + } + + /** + * Called when the device leaves a state where a PIN, pattern or + * password must be entered to unlock it. + */ + public void onDeviceUnlocked() { + } + private void onError(String msg) { Slog.v(TAG, "Remote exception while " + msg); } @@ -300,6 +322,16 @@ public class TrustAgentService extends Service { .sendToTarget(); } + @Override + public void onDeviceLocked() throws RemoteException { + mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget(); + } + + @Override + public void onDeviceUnlocked() throws RemoteException { + mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget(); + } + @Override /* Binder API */ public void setCallback(ITrustAgentServiceCallback callback) { synchronized (mLock) { diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 275dab0..9496b53 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -23,6 +23,7 @@ import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.ViewRootImpl; import android.view.WindowInsets; + import com.android.internal.R; import com.android.internal.os.HandlerCaller; import com.android.internal.view.BaseIWindow; @@ -32,18 +33,17 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.app.WallpaperManager; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.Bundle; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.PowerManager; import android.os.RemoteException; import android.util.Log; import android.view.Display; @@ -139,7 +139,6 @@ public abstract class WallpaperService extends Service { boolean mInitializing = true; boolean mVisible; - boolean mScreenOn = true; boolean mReportedVisible; boolean mDestroyed; @@ -191,20 +190,10 @@ public abstract class WallpaperService extends Service { float mPendingYOffsetStep; boolean mPendingSync; MotionEvent mPendingMove; - - final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { - mScreenOn = true; - reportVisibility(); - } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { - mScreenOn = false; - reportVisibility(); - } - } - }; - + + DisplayManager mDisplayManager; + Display mDisplay; + final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { { mRequestedFormat = PixelFormat.RGBX_8888; @@ -536,8 +525,8 @@ public abstract class WallpaperService extends Service { out.print(prefix); out.print("mInitializing="); out.print(mInitializing); out.print(" mDestroyed="); out.println(mDestroyed); out.print(prefix); out.print("mVisible="); out.print(mVisible); - out.print(" mScreenOn="); out.print(mScreenOn); out.print(" mReportedVisible="); out.println(mReportedVisible); + out.print(prefix); out.print("mDisplay="); out.println(mDisplay); out.print(prefix); out.print("mCreated="); out.print(mCreated); out.print(" mSurfaceCreated="); out.print(mSurfaceCreated); out.print(" mIsCreating="); out.print(mIsCreating); @@ -876,13 +865,10 @@ public abstract class WallpaperService extends Service { mWindow.setSession(mSession); - mScreenOn = ((PowerManager)getSystemService(Context.POWER_SERVICE)).isScreenOn(); + mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); + mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler()); + mDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - registerReceiver(mReceiver, filter); - if (DEBUG) Log.v(TAG, "onCreate(): " + this); onCreate(mSurfaceHolder); @@ -921,7 +907,8 @@ public abstract class WallpaperService extends Service { void reportVisibility() { if (!mDestroyed) { - boolean visible = mVisible && mScreenOn; + boolean visible = mVisible + & mDisplay != null && mDisplay.getState() != Display.STATE_OFF; if (mReportedVisible != visible) { mReportedVisible = visible; if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible @@ -1024,7 +1011,11 @@ public abstract class WallpaperService extends Service { } mDestroyed = true; - + + if (mDisplayManager != null) { + mDisplayManager.unregisterDisplayListener(mDisplayListener); + } + if (mVisible) { mVisible = false; if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this); @@ -1035,9 +1026,7 @@ public abstract class WallpaperService extends Service { if (DEBUG) Log.v(TAG, "onDestroy(): " + this); onDestroy(); - - unregisterReceiver(mReceiver); - + if (mCreated) { try { if (DEBUG) Log.v(TAG, "Removing window and destroying surface " @@ -1062,8 +1051,25 @@ public abstract class WallpaperService extends Service { } } } + + private final DisplayListener mDisplayListener = new DisplayListener() { + @Override + public void onDisplayChanged(int displayId) { + if (mDisplay.getDisplayId() == displayId) { + reportVisibility(); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + } + + @Override + public void onDisplayAdded(int displayId) { + } + }; } - + class IWallpaperEngineWrapper extends IWallpaperEngine.Stub implements HandlerCaller.Callback { private final HandlerCaller mCaller; diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 933bcee..72bbb2b 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -17,6 +17,7 @@ package android.text.format; import android.content.Context; +import android.os.UserHandle; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -166,8 +167,20 @@ public class DateFormat { * @return true if 24 hour time format is selected, false otherwise. */ public static boolean is24HourFormat(Context context) { - String value = Settings.System.getString(context.getContentResolver(), - Settings.System.TIME_12_24); + return is24HourFormat(context, UserHandle.myUserId()); + } + + /** + * Returns true if user preference with the given user handle is set to 24-hour format. + * @param context the context to use for the content resolver + * @param userHandle the user handle of the user to query. + * @return true if 24 hour time format is selected, false otherwise. + * + * @hide + */ + public static boolean is24HourFormat(Context context, int userHandle) { + String value = Settings.System.getStringForUser(context.getContentResolver(), + Settings.System.TIME_12_24, userHandle); if (value == null) { Locale locale = context.getResources().getConfiguration().locale; @@ -179,7 +192,7 @@ public class DateFormat { } java.text.DateFormat natural = - java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale); + java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale); if (natural instanceof SimpleDateFormat) { SimpleDateFormat sdf = (SimpleDateFormat) natural; @@ -253,8 +266,19 @@ public class DateFormat { * @hide */ public static String getTimeFormatString(Context context) { + return getTimeFormatString(context, UserHandle.myUserId()); + } + + /** + * Returns a String pattern that can be used to format the time according + * to the current locale and the user's 12-/24-hour clock preference. + * @param context the application context + * @param userHandle the user handle of the user to query the format for + * @hide + */ + public static String getTimeFormatString(Context context, int userHandle) { LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - return is24HourFormat(context) ? d.timeFormat24 : d.timeFormat12; + return is24HourFormat(context, userHandle) ? d.timeFormat24 : d.timeFormat12; } /** diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index d120d79..9061679 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -216,7 +216,7 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// @Override - public int callDrawGLFunction(long drawGLFunction) { + public int callDrawGLFunction2(long drawGLFunction) { return nCallDrawGLFunction(mRenderer, drawGLFunction); } @@ -997,15 +997,4 @@ class GLES20Canvas extends HardwareCanvas { int indexOffset, int indexCount, Paint paint) { // TODO: Implement } - - @Override - public void setOverrideXfermode(PorterDuff.Mode xfermode) { - int xfermodeValue = -1; - if (xfermode != null) { - xfermodeValue = xfermode.nativeInt; - } - nSetOverrideXfermode(mRenderer, xfermodeValue); - } - - private static native void nSetOverrideXfermode(long renderer, int xfermode); } diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index e3eee71..18accb8 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -105,10 +105,7 @@ public abstract class HardwareCanvas extends Canvas { * * @hide */ - public int callDrawGLFunction(long drawGLFunction) { - // Noop - this is done in the display list recorder subclass - return RenderNode.STATUS_DONE; - } + public abstract int callDrawGLFunction2(long drawGLFunction); public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy, CanvasProperty<Float> radius, CanvasProperty<Paint> paint); diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index b95f9a4..7feca30 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -189,9 +189,6 @@ public class RenderNodeAnimator extends Animator { } private void doStart() { - mState = STATE_RUNNING; - nStart(mNativePtr.get(), this); - // Alpha is a special snowflake that has the canonical value stored // in mTransformationInfo instead of in RenderNode, so we need to update // it with the final value here. @@ -201,7 +198,7 @@ public class RenderNodeAnimator extends Animator { mViewTarget.mTransformationInfo.mAlpha = mFinalValue; } - notifyStartListeners(); + moveToRunningState(); if (mViewTarget != null) { // Kick off a frame to start the process @@ -209,6 +206,12 @@ public class RenderNodeAnimator extends Animator { } } + private void moveToRunningState() { + mState = STATE_RUNNING; + nStart(mNativePtr.get(), this); + notifyStartListeners(); + } + private void notifyStartListeners() { final ArrayList<AnimatorListener> listeners = cloneListeners(); final int numListeners = listeners == null ? 0 : listeners.size(); @@ -222,7 +225,7 @@ public class RenderNodeAnimator extends Animator { if (mState != STATE_PREPARE && mState != STATE_FINISHED) { if (mState == STATE_DELAYED) { getHelper().removeDelayedAnimation(this); - notifyStartListeners(); + moveToRunningState(); } nEnd(mNativePtr.get()); @@ -242,7 +245,15 @@ public class RenderNodeAnimator extends Animator { @Override public void end() { if (mState != STATE_FINISHED) { + if (mState < STATE_RUNNING) { + getHelper().removeDelayedAnimation(this); + doStart(); + } nEnd(mNativePtr.get()); + if (mViewTarget != null) { + // Kick off a frame to flush the state change + mViewTarget.invalidateViewProperty(true, false); + } } } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 2c8a499..131c039 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -340,6 +340,7 @@ public class ThreadedRenderer extends HardwareRenderer { recordDuration, view.getResources().getDisplayMetrics().density); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { setEnabled(false); + attachInfo.mViewRootImpl.mSurface.release(); // Invalidate since we failed to draw. This should fetch a Surface // if it is still needed or do nothing if we are no longer drawing attachInfo.mViewRootImpl.invalidate(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index fe17417..b12c747 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -245,7 +245,7 @@ public final class ViewRootImpl implements ViewParent, // These can be accessed by any thread, must be protected with a lock. // Surface can never be reassigned or cleared (use Surface.clear()). - private final Surface mSurface = new Surface(); + final Surface mSurface = new Surface(); boolean mAdded; boolean mAddedTouchMode; diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index b85fec8..521fd31 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -37,6 +37,8 @@ public final class ViewTreeObserver { private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners; private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners; private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners; + private CopyOnWriteArrayList<OnEnterAnimationCompleteListener> + mOnEnterAnimationCompleteListeners; // Non-recursive listeners use CopyOnWriteArray // Any listener invoked from ViewRootImpl.performTraversals() should not be recursive @@ -316,6 +318,13 @@ public final class ViewTreeObserver { } /** + * @hide + */ + public interface OnEnterAnimationCompleteListener { + public void onEnterAnimationComplete(); + } + + /** * Creates a new ViewTreeObserver. This constructor should not be called */ ViewTreeObserver() { @@ -780,6 +789,29 @@ public final class ViewTreeObserver { mOnComputeInternalInsetsListeners.remove(victim); } + /** + * @hide + */ + public void addOnEnterAnimationCompleteListener(OnEnterAnimationCompleteListener listener) { + checkIsAlive(); + if (mOnEnterAnimationCompleteListeners == null) { + mOnEnterAnimationCompleteListeners = + new CopyOnWriteArrayList<OnEnterAnimationCompleteListener>(); + } + mOnEnterAnimationCompleteListeners.add(listener); + } + + /** + * @hide + */ + public void removeOnEnterAnimationCompleteListener(OnEnterAnimationCompleteListener listener) { + checkIsAlive(); + if (mOnEnterAnimationCompleteListeners == null) { + return; + } + mOnEnterAnimationCompleteListeners.remove(listener); + } + private void checkIsAlive() { if (!mAlive) { throw new IllegalStateException("This ViewTreeObserver is not alive, call " @@ -1022,6 +1054,23 @@ public final class ViewTreeObserver { } /** + * @hide + */ + public final void dispatchOnEnterAnimationComplete() { + // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to + // perform the dispatching. The iterator is a safe guard against listeners that + // could mutate the list by calling the various add/remove methods. This prevents + // the array from being modified while we iterate it. + final CopyOnWriteArrayList<OnEnterAnimationCompleteListener> listeners = + mOnEnterAnimationCompleteListeners; + if (listeners != null && !listeners.isEmpty()) { + for (OnEnterAnimationCompleteListener listener : listeners) { + listener.onEnterAnimationComplete(); + } + } + } + + /** * Copy on write array. This array is not thread safe, and only one loop can * iterate over this array at any given time. This class avoids allocations * until a concurrent modification happens. diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 0076abf..2e5c1e0 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; @@ -155,6 +156,7 @@ public abstract class Window { "android:navigation:background"; /** The default features enabled */ + @Deprecated @SuppressWarnings({"PointlessBitwiseExpression"}) protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) | (1 << FEATURE_CONTEXT_MENU); @@ -183,8 +185,8 @@ public abstract class Window { private boolean mSetCloseOnTouchOutside = false; private int mForcedWindowFlags = 0; - private int mFeatures = DEFAULT_FEATURES; - private int mLocalFeatures = DEFAULT_FEATURES; + private int mFeatures; + private int mLocalFeatures; private boolean mHaveWindowFormat = false; private boolean mHaveDimAmount = false; @@ -442,6 +444,7 @@ public abstract class Window { public Window(Context context) { mContext = context; + mFeatures = mLocalFeatures = getDefaultFeatures(context); } /** @@ -1270,6 +1273,25 @@ public abstract class Window { } /** + * Return the feature bits set by default on a window. + * @param context The context used to access resources + */ + public static int getDefaultFeatures(Context context) { + int features = 0; + + final Resources res = context.getResources(); + if (res.getBoolean(com.android.internal.R.bool.config_defaultWindowFeatureOptionsPanel)) { + features |= 1 << FEATURE_OPTIONS_PANEL; + } + + if (res.getBoolean(com.android.internal.R.bool.config_defaultWindowFeatureContextMenu)) { + features |= 1 << FEATURE_CONTEXT_MENU; + } + + return features; + } + + /** * Query for the availability of a certain feature. * * @param feature The feature ID to check diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 8e27834..0d82087 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -118,9 +118,6 @@ public final class WindowManagerGlobal { private Runnable mSystemPropertyUpdater; - /** Default token to apply to added views. */ - private IBinder mDefaultToken; - private WindowManagerGlobal() { } @@ -181,17 +178,6 @@ public final class WindowManagerGlobal { } } - /** - * Sets the default token to use in {@link #addView} when no parent window - * token is available and no token has been explicitly set in the view's - * layout params. - * - * @param token Default window token to apply to added views. - */ - public void setDefaultToken(IBinder token) { - mDefaultToken = token; - } - public String[] getViewRootNames() { synchronized (mLock) { final int numRoots = mRoots.size(); @@ -239,10 +225,6 @@ public final class WindowManagerGlobal { } } - if (wparams.token == null && mDefaultToken != null) { - wparams.token = mDefaultToken; - } - ViewRootImpl root; View panelParentView = null; diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 52d79f8..98e9f54 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -16,6 +16,9 @@ package android.view; +import android.annotation.NonNull; +import android.os.IBinder; + /** * Provides low-level communication with the system window manager for * operations that are bound to a particular context, display or parent window. @@ -47,6 +50,8 @@ public final class WindowManagerImpl implements WindowManager { private final Display mDisplay; private final Window mParentWindow; + private IBinder mDefaultToken; + public WindowManagerImpl(Display display) { this(display, null); } @@ -64,16 +69,43 @@ public final class WindowManagerImpl implements WindowManager { return new WindowManagerImpl(display, mParentWindow); } + /** + * Sets the window token to assign when none is specified by the client or + * available from the parent window. + * + * @param token The default token to assign. + */ + public void setDefaultToken(IBinder token) { + mDefaultToken = token; + } + @Override - public void addView(View view, ViewGroup.LayoutParams params) { + public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { + applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); } @Override - public void updateViewLayout(View view, ViewGroup.LayoutParams params) { + public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { + applyDefaultToken(params); mGlobal.updateViewLayout(view, params); } + private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) { + // Only use the default token if we don't have a parent window. + if (mDefaultToken != null && mParentWindow == null) { + if (!(params instanceof WindowManager.LayoutParams)) { + throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); + } + + // Only use the default token if we don't already have a token. + final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; + if (wparams.token == null) { + wparams.token = mDefaultToken; + } + } + } + @Override public void removeView(View view) { mGlobal.removeView(view, false); diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index 3dcfda3..e03445e 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -107,7 +107,7 @@ public final class WebViewDelegate { throw new IllegalArgumentException(canvas.getClass().getName() + " is not hardware accelerated"); } - ((HardwareCanvas) canvas).callDrawGLFunction(nativeDrawGLFunctor); + ((HardwareCanvas) canvas).callDrawGLFunction2(nativeDrawGLFunctor); } /** diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java index d779124..18f15a0 100644 --- a/core/java/android/widget/ActionMenuPresenter.java +++ b/core/java/android/widget/ActionMenuPresenter.java @@ -655,15 +655,19 @@ public class ActionMenuPresenter extends BaseMenuPresenter protected boolean setFrame(int l, int t, int r, int b) { final boolean changed = super.setFrame(l, t, r, b); - // Set up the hotspot bounds to be centered on the image. + // Set up the hotspot bounds to square and centered on the image. final Drawable d = getDrawable(); final Drawable bg = getBackground(); if (d != null && bg != null) { - final float[] pts = mTempPts; - pts[0] = d.getBounds().centerX(); - getImageMatrix().mapPoints(pts); - final int offset = (int) pts[0] - getWidth() / 2; - bg.setHotspotBounds(offset, 0, getWidth() + offset, getHeight()); + final int width = getWidth(); + final int height = getHeight(); + final int halfEdge = Math.max(width, height) / 2; + final int offsetX = getPaddingLeft() - getPaddingRight(); + final int offsetY = getPaddingTop() - getPaddingBottom(); + final int centerX = (width + offsetX) / 2; + final int centerY = (height + offsetY) / 2; + bg.setHotspotBounds(centerX - halfEdge, centerY - halfEdge, + centerX + halfEdge, centerY + halfEdge); } return changed; diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 06bb32c..fe143de 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -106,6 +106,9 @@ class FastScroller { */ private final int[] mPreviewResId = new int[2]; + /** The minimum touch target size in pixels. */ + private final int mMinimumTouchTarget; + /** * Padding in pixels around the preview text. Applied as layout margins to * the preview text and padding to the preview image. @@ -254,6 +257,9 @@ class FastScroller { mPrimaryText = createPreviewTextView(context); mSecondaryText = createPreviewTextView(context); + mMinimumTouchTarget = listView.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.fast_scroller_minimum_touch_target); + setStyle(styleResId); final ViewGroupOverlay overlay = listView.getOverlay(); @@ -1474,10 +1480,18 @@ class FastScroller { } private boolean isPointInsideX(float x) { + final float offset = mThumbImage.getTranslationX(); + final float left = mThumbImage.getLeft() + offset; + final float right = mThumbImage.getRight() + offset; + + // Apply the minimum touch target size. + final float targetSizeDiff = mMinimumTouchTarget - (right - left); + final float adjust = targetSizeDiff > 0 ? targetSizeDiff : 0; + if (mLayoutFromRight) { - return x >= mThumbImage.getLeft(); + return x >= mThumbImage.getLeft() - adjust; } else { - return x <= mThumbImage.getRight(); + return x <= mThumbImage.getRight() + adjust; } } @@ -1485,7 +1499,12 @@ class FastScroller { final float offset = mThumbImage.getTranslationY(); final float top = mThumbImage.getTop() + offset; final float bottom = mThumbImage.getBottom() + offset; - return y >= top && y <= bottom; + + // Apply the minimum touch target size. + final float targetSizeDiff = mMinimumTouchTarget - (bottom - top); + final float adjust = targetSizeDiff > 0 ? targetSizeDiff / 2 : 0; + + return y >= (top - adjust) && y <= (bottom + adjust); } /** diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index defc26c..161ae7e 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -1613,7 +1613,11 @@ public class GridLayout extends ViewGroup { equivalent to the single-source shortest paths problem on a digraph, for which the O(n^2) Bellman-Ford algorithm the most commonly used general solution. */ - private void solve(Arc[] arcs, int[] locations) { + private boolean solve(Arc[] arcs, int[] locations) { + return solve(arcs, locations, true); + } + + private boolean solve(Arc[] arcs, int[] locations, boolean modifyOnError) { String axisName = horizontal ? "horizontal" : "vertical"; int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1. boolean[] originalCulprits = null; @@ -1631,10 +1635,14 @@ public class GridLayout extends ViewGroup { if (originalCulprits != null) { logError(axisName, arcs, originalCulprits); } - return; + return true; } } + if (!modifyOnError) { + return false; // cannot solve with these constraints + } + boolean[] culprits = new boolean[arcs.length]; for (int i = 0; i < N; i++) { for (int j = 0, length = arcs.length; j < length; j++) { @@ -1658,6 +1666,7 @@ public class GridLayout extends ViewGroup { } } } + return true; } private void computeMargins(boolean leading) { @@ -1697,8 +1706,8 @@ public class GridLayout extends ViewGroup { return trailingMargins; } - private void solve(int[] a) { - solve(getArcs(), a); + private boolean solve(int[] a) { + return solve(getArcs(), a); } private boolean computeHasWeights() { @@ -1740,28 +1749,18 @@ public class GridLayout extends ViewGroup { return deltas; } - private void shareOutDelta() { - int totalDelta = 0; - float totalWeight = 0; + private void shareOutDelta(int totalDelta, float totalWeight) { + Arrays.fill(deltas, 0); for (int i = 0, N = getChildCount(); i < N; i++) { View c = getChildAt(i); LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; float weight = spec.weight; if (weight != 0) { - int delta = getMeasurement(c, horizontal) - getOriginalMeasurements()[i]; - totalDelta += delta; - totalWeight += weight; - } - } - for (int i = 0, N = getChildCount(); i < N; i++) { - LayoutParams lp = getLayoutParams(getChildAt(i)); - Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; - float weight = spec.weight; - if (weight != 0) { int delta = Math.round((weight * totalDelta / totalWeight)); deltas[i] = delta; - // the two adjustments below are to counter the above rounding and avoid off-by-ones at the end + // the two adjustments below are to counter the above rounding and avoid + // off-by-ones at the end totalDelta -= delta; totalWeight -= weight; } @@ -1771,12 +1770,46 @@ public class GridLayout extends ViewGroup { private void solveAndDistributeSpace(int[] a) { Arrays.fill(getDeltas(), 0); solve(a); - shareOutDelta(); - arcsValid = false; - forwardLinksValid = false; - backwardLinksValid = false; - groupBoundsValid = false; - solve(a); + int deltaMax = parentMin.value * getChildCount() + 1; //exclusive + if (deltaMax < 2) { + return; //don't have any delta to distribute + } + int deltaMin = 0; //inclusive + + float totalWeight = calculateTotalWeight(); + + int validDelta = -1; //delta for which a solution exists + boolean validSolution = true; + // do a binary search to find the max delta that won't conflict with constraints + while(deltaMin < deltaMax) { + final int delta = (deltaMin + deltaMax) / 2; + invalidateValues(); + shareOutDelta(delta, totalWeight); + validSolution = solve(getArcs(), a, false); + if (validSolution) { + validDelta = delta; + deltaMin = delta + 1; + } else { + deltaMax = delta; + } + } + if (validDelta > 0 && !validSolution) { + // last solution was not successful but we have a successful one. Use it. + invalidateValues(); + shareOutDelta(validDelta, totalWeight); + solve(a); + } + } + + private float calculateTotalWeight() { + float totalWeight = 0f; + for (int i = 0, N = getChildCount(); i < N; i++) { + View c = getChildAt(i); + LayoutParams lp = getLayoutParams(c); + Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; + totalWeight += spec.weight; + } + return totalWeight; } private void computeLocations(int[] a) { diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 4c5c71d..a98d272 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -16,6 +16,7 @@ package android.widget; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -26,6 +27,7 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.text.format.DateFormat; import android.util.AttributeSet; @@ -127,6 +129,8 @@ public class TextClock extends TextView { private Calendar mTime; private String mTimeZone; + private boolean mShowCurrentUserTime; + private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { @@ -342,6 +346,22 @@ public class TextClock extends TextView { } /** + * Sets whether this clock should always track the current user and not the user of the + * current process. This is used for single instance processes like the systemUI who need + * to display time for different users. + * + * @hide + */ + public void setShowCurrentUserTime(boolean showCurrentUserTime) { + mShowCurrentUserTime = showCurrentUserTime; + + chooseFormat(); + onTimeChanged(); + unregisterObserver(); + registerObserver(); + } + + /** * Indicates whether the system is currently using the 24-hour mode. * * When the system is in 24-hour mode, this view will use the pattern @@ -360,7 +380,11 @@ public class TextClock extends TextView { * @see #getFormat24Hour() */ public boolean is24HourModeEnabled() { - return DateFormat.is24HourFormat(getContext()); + if (mShowCurrentUserTime) { + return DateFormat.is24HourFormat(getContext(), ActivityManager.getCurrentUser()); + } else { + return DateFormat.is24HourFormat(getContext()); + } } /** @@ -500,7 +524,13 @@ public class TextClock extends TextView { private void registerObserver() { final ContentResolver resolver = getContext().getContentResolver(); - resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver); + if (mShowCurrentUserTime) { + resolver.registerContentObserver(Settings.System.CONTENT_URI, true, + mFormatChangeObserver, UserHandle.USER_ALL); + } else { + resolver.registerContentObserver(Settings.System.CONTENT_URI, true, + mFormatChangeObserver); + } } private void unregisterReceiver() { |
