summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManager.java9
-rw-r--r--core/java/android/app/ApplicationPackageManager.java35
-rw-r--r--core/java/android/app/Notification.java4
-rw-r--r--core/java/android/app/backup/BackupManager.java141
-rw-r--r--core/java/android/app/backup/BackupTransport.java21
-rw-r--r--core/java/android/app/backup/RestoreDescription.java2
-rw-r--r--core/java/android/app/backup/RestoreObserver.java3
-rw-r--r--core/java/android/app/backup/RestoreSession.java2
-rw-r--r--core/java/android/app/backup/RestoreSet.java2
-rw-r--r--core/java/android/app/trust/ITrustListener.aidl2
-rw-r--r--core/java/android/app/trust/TrustManager.java24
-rw-r--r--core/java/android/bluetooth/BluetoothGattCallbackWrapper.java3
-rw-r--r--core/java/android/bluetooth/IBluetoothGatt.aidl4
-rw-r--r--core/java/android/bluetooth/IBluetoothGattCallback.aidl3
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java77
-rw-r--r--core/java/android/bluetooth/le/ResultStorageDescriptor.aidl23
-rw-r--r--core/java/android/bluetooth/le/ResultStorageDescriptor.java93
-rw-r--r--core/java/android/bluetooth/le/TruncatedFilter.java61
-rw-r--r--core/java/android/content/ContentResolver.java2
-rw-r--r--core/java/android/content/Context.java1
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl3
-rw-r--r--core/java/android/content/pm/InstallSessionInfo.java9
-rw-r--r--core/java/android/content/pm/LauncherApps.java14
-rw-r--r--core/java/android/content/pm/PackageInstaller.java55
-rw-r--r--core/java/android/content/pm/PackageManager.java67
-rw-r--r--core/java/android/content/res/ColorStateList.java2
-rw-r--r--core/java/android/content/res/Resources.java28
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java207
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java74
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java193
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java86
-rw-r--r--core/java/android/hardware/camera2/impl/ListenerProxies.java16
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java231
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java3
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java42
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java14
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java14
-rw-r--r--core/java/android/hardware/camera2/legacy/ParameterUtils.java62
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java71
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java7
-rw-r--r--core/java/android/hardware/display/DisplayManager.java53
-rw-r--r--core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl8
-rw-r--r--core/java/android/net/TrafficStats.java13
-rw-r--r--core/java/android/os/BatteryStats.java109
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/UserHandle.java11
-rw-r--r--core/java/android/os/UserManager.java9
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java76
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java1
-rw-r--r--core/java/android/view/GLES20Canvas.java3
-rw-r--r--core/java/android/view/RenderNode.java6
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/WindowInsets.java1
-rw-r--r--core/java/android/webkit/WebViewFactory.java56
-rw-r--r--core/java/android/widget/AbsListView.java36
-rw-r--r--core/java/android/widget/DatePicker.java29
-rw-r--r--core/java/android/widget/DatePickerCalendarDelegate.java (renamed from core/java/android/widget/DatePickerDelegate.java)4
-rw-r--r--core/java/android/widget/GridView.java5
-rw-r--r--core/java/android/widget/MediaController.java74
-rw-r--r--core/java/android/widget/ScrollView.java8
-rw-r--r--core/java/android/widget/TextView.java11
-rw-r--r--core/java/android/widget/TimePicker.java21
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java (renamed from core/java/android/widget/LegacyTimePickerDelegate.java)12
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java (renamed from core/java/android/widget/TimePickerDelegate.java)12
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl3
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java34
-rw-r--r--core/java/com/android/internal/os/AtomicFile.java13
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java135
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java260
-rw-r--r--core/java/com/android/internal/util/JournaledFile.java2
71 files changed, 2071 insertions, 667 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index fc200550..3bf8e2e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -700,6 +700,13 @@ public class ActivityManager {
*/
public int affiliatedTaskId;
+ /**
+ * Task affiliation color of the source task with the affiliated task id.
+ *
+ * @hide
+ */
+ public int affiliatedTaskColor;
+
public RecentTaskInfo() {
}
@@ -732,6 +739,7 @@ public class ActivityManager {
dest.writeLong(firstActiveTime);
dest.writeLong(lastActiveTime);
dest.writeInt(affiliatedTaskId);
+ dest.writeInt(affiliatedTaskColor);
}
public void readFromParcel(Parcel source) {
@@ -747,6 +755,7 @@ public class ActivityManager {
firstActiveTime = source.readLong();
lastActiveTime = source.readLong();
affiliatedTaskId = source.readInt();
+ affiliatedTaskColor = source.readInt();
}
public static final Creator<RecentTaskInfo> CREATOR
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 84b5516..a935dc0 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -28,7 +28,6 @@ import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
@@ -53,7 +52,6 @@ import android.content.res.XmlResourceParser;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -1655,39 +1653,6 @@ final class ApplicationPackageManager extends PackageManager {
new UserHandle(mContext.getUserId()));
}
- private static class LegacyPackageInstallObserver extends PackageInstallObserver {
- private final IPackageInstallObserver mLegacy;
-
- public LegacyPackageInstallObserver(IPackageInstallObserver legacy) {
- mLegacy = legacy;
- }
-
- @Override
- public void onPackageInstalled(String basePackageName, int returnCode, String msg,
- Bundle extras) {
- try {
- mLegacy.packageInstalled(basePackageName, returnCode);
- } catch (RemoteException ignored) {
- }
- }
- }
-
- private static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
- private final IPackageDeleteObserver mLegacy;
-
- public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
- mLegacy = legacy;
- }
-
- @Override
- public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
- try {
- mLegacy.packageDeleted(basePackageName, returnCode);
- } catch (RemoteException ignored) {
- }
- }
- }
-
private final ContextImpl mContext;
private final IPackageManager mPM;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5684a7a..90b8b86 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -32,7 +32,6 @@ import android.media.AudioManager;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1900,8 +1899,7 @@ public class Notification implements Parcelable
mPriority = PRIORITY_DEFAULT;
mPeople = new ArrayList<String>();
- mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
- NotificationColorUtil.getInstance() : null;
+ mColorUtil = NotificationColorUtil.getInstance();
}
/**
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index be8108c..e9297b9 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.SystemApi;
import android.app.backup.RestoreSession;
import android.app.backup.IBackupManager;
import android.app.backup.IRestoreSession;
@@ -114,7 +115,7 @@ public class BackupManager {
try {
sService.dataChanged(packageName);
} catch (RemoteException e) {
- Log.d(TAG, "dataChanged(pkg) couldn't connect");
+ Log.e(TAG, "dataChanged(pkg) couldn't connect");
}
}
}
@@ -150,7 +151,7 @@ public class BackupManager {
result = session.restorePackage(mContext.getPackageName(), observer);
}
} catch (RemoteException e) {
- Log.w(TAG, "restoreSelf() unable to contact service");
+ Log.e(TAG, "restoreSelf() unable to contact service");
} finally {
if (session != null) {
session.endRestoreSession();
@@ -160,11 +161,14 @@ public class BackupManager {
return result;
}
+ // system APIs start here
+
/**
* Begin the process of restoring data from backup. See the
* {@link android.app.backup.RestoreSession} class for documentation on that process.
* @hide
*/
+ @SystemApi
public RestoreSession beginRestoreSession() {
RestoreSession session = null;
checkServiceBinder();
@@ -176,9 +180,140 @@ public class BackupManager {
session = new RestoreSession(mContext, binder);
}
} catch (RemoteException e) {
- Log.w(TAG, "beginRestoreSession() couldn't connect");
+ Log.e(TAG, "beginRestoreSession() couldn't connect");
}
}
return session;
}
+
+ /**
+ * Enable/disable the backup service entirely. When disabled, no backup
+ * or restore operations will take place. Data-changed notifications will
+ * still be observed and collected, however, so that changes made while the
+ * mechanism was disabled will still be backed up properly if it is enabled
+ * at some point in the future.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void setBackupEnabled(boolean isEnabled) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ sService.setBackupEnabled(isEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setBackupEnabled() couldn't connect");
+ }
+ }
+ }
+
+ /**
+ * Report whether the backup mechanism is currently enabled.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isBackupEnabled() {
+ if (sService != null) {
+ try {
+ return sService.isBackupEnabled();
+ } catch (RemoteException e) {
+ Log.e(TAG, "isBackupEnabled() couldn't connect");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Identify the currently selected transport. Callers must hold the
+ * android.permission.BACKUP permission to use this method.
+ * @return The name of the currently active backup transport. In case of
+ * failure or if no transport is currently active, this method returns {@code null}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public String getCurrentTransport() {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ return sService.getCurrentTransport();
+ } catch (RemoteException e) {
+ Log.e(TAG, "getCurrentTransport() couldn't connect");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Request a list of all available backup transports' names. Callers must
+ * hold the android.permission.BACKUP permission to use this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ public String[] listAllTransports() {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ return sService.listAllTransports();
+ } catch (RemoteException e) {
+ Log.e(TAG, "listAllTransports() couldn't connect");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Specify the current backup transport. Callers must hold the
+ * android.permission.BACKUP permission to use this method.
+ *
+ * @param transport The name of the transport to select. This should be one
+ * of the names returned by {@link #listAllTransports()}.
+ * @return The name of the previously selected transport. If the given transport
+ * name is not one of the currently available transports, no change is made to
+ * the current transport setting and the method returns null.
+ *
+ * @hide
+ */
+ @SystemApi
+ public String selectBackupTransport(String transport) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ return sService.selectBackupTransport(transport);
+ } catch (RemoteException e) {
+ Log.e(TAG, "selectBackupTransport() couldn't connect");
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Schedule an immediate backup attempt for all pending key/value updates. This
+ * is primarily intended for transports to use when they detect a suitable
+ * opportunity for doing a backup pass. If there are no pending updates to
+ * be sent, no action will be taken. Even if some updates are pending, the
+ * transport will still be asked to confirm via the usual requestBackupTime()
+ * method.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void backupNow() {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ sService.backupNow();
+ } catch (RemoteException e) {
+ Log.e(TAG, "backupNow() couldn't connect");
+ }
+ }
+ }
}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 446c03e..6adc2e0 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.SystemApi;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.IBinder;
@@ -30,6 +31,7 @@ import com.android.internal.backup.IBackupTransport;
*
* @hide
*/
+@SystemApi
public class BackupTransport {
// Zero return always means things are okay. If returned from
// getNextFullRestoreDataChunk(), it means that no data could be delivered at
@@ -403,6 +405,25 @@ public class BackupTransport {
return BackupTransport.TRANSPORT_ERROR;
}
+ /**
+ * Tells the transport to cancel the currently-ongoing full backup operation. This
+ * will happen between {@link #performFullBackup()} and {@link #finishBackup()}
+ * if the OS needs to abort the backup operation for any reason, such as a crash in
+ * the application undergoing backup.
+ *
+ * <p>When it receives this call, the transport should discard any partial archive
+ * that it has stored so far. If possible it should also roll back to the previous
+ * known-good archive in its datastore.
+ *
+ * <p>If the transport receives this callback, it will <em>not</em> receive a
+ * call to {@link #finishBackup()}. It needs to tear down any ongoing backup state
+ * here.
+ */
+ public void cancelFullBackup() {
+ throw new UnsupportedOperationException(
+ "Transport cancelFullBackup() not implemented");
+ }
+
// ------------------------------------------------------------------------------------
// Full restore interfaces
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
index 50ab0b4..611ff07 100644
--- a/core/java/android/app/backup/RestoreDescription.java
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@ import android.os.Parcelable;
*
* @hide
*/
+@SystemApi
public class RestoreDescription implements Parcelable {
private final String mPackageName;
private final int mDataType;
diff --git a/core/java/android/app/backup/RestoreObserver.java b/core/java/android/app/backup/RestoreObserver.java
index dbddb78..b4a23d0 100644
--- a/core/java/android/app/backup/RestoreObserver.java
+++ b/core/java/android/app/backup/RestoreObserver.java
@@ -17,6 +17,8 @@
package android.app.backup;
import java.lang.String;
+
+import android.annotation.SystemApi;
import android.app.backup.RestoreSet;
/**
@@ -36,6 +38,7 @@ public abstract class RestoreObserver {
*
* @hide
*/
+ @SystemApi
public void restoreSetsAvailable(RestoreSet[] result) {
}
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 7181c61..0a885b6 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.SystemApi;
import android.app.backup.RestoreObserver;
import android.app.backup.RestoreSet;
import android.app.backup.IRestoreObserver;
@@ -30,6 +31,7 @@ import android.util.Log;
* Interface for managing a restore session.
* @hide
*/
+@SystemApi
public class RestoreSession {
static final String TAG = "RestoreSession";
diff --git a/core/java/android/app/backup/RestoreSet.java b/core/java/android/app/backup/RestoreSet.java
index 0431977..aacaf7c 100644
--- a/core/java/android/app/backup/RestoreSet.java
+++ b/core/java/android/app/backup/RestoreSet.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,6 +26,7 @@ import android.os.Parcelable;
*
* @hide
*/
+@SystemApi
public class RestoreSet implements Parcelable {
/**
* Name of this restore set. May be user generated, may simply be the name
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
index 45a066d..d80f58c 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -22,6 +22,6 @@ package android.app.trust;
* {@hide}
*/
oneway interface ITrustListener {
- void onTrustChanged(boolean enabled, int userId);
+ void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
void onTrustManagedChanged(boolean managed, int userId);
} \ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 796e3cc..3d262b1 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -34,6 +34,7 @@ public class TrustManager {
private static final int MSG_TRUST_MANAGED_CHANGED = 2;
private static final String TAG = "TrustManager";
+ private static final String DATA_INITIATED_BY_USER = "initiatedByUser";
private final ITrustManager mService;
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -95,14 +96,17 @@ public class TrustManager {
try {
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
@Override
- public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
- mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
- trustListener).sendToTarget();
+ public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+ Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
+ trustListener);
+ if (initiatedByUser) {
+ m.getData().putBoolean(DATA_INITIATED_BY_USER, initiatedByUser);
+ }
+ m.sendToTarget();
}
@Override
- public void onTrustManagedChanged(boolean managed, int userId)
- throws RemoteException {
+ public void onTrustManagedChanged(boolean managed, int userId) {
mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId,
trustListener).sendToTarget();
}
@@ -139,7 +143,11 @@ public class TrustManager {
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_TRUST_CHANGED:
- ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
+ boolean initiatedByUser = msg.peekData() != null &&
+ msg.peekData().getBoolean(DATA_INITIATED_BY_USER);
+ ((TrustListener)msg.obj).onTrustChanged(
+ msg.arg1 != 0, msg.arg2, initiatedByUser);
+
break;
case MSG_TRUST_MANAGED_CHANGED:
((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
@@ -153,8 +161,10 @@ public class TrustManager {
* Reports that the trust state has changed.
* @param enabled if true, the system believes the environment to be trusted.
* @param userId the user, for which the trust changed.
+ * @param initiatedByUser indicates that the user has explicitly initiated an action that
+ * proves the user is about to use the device.
*/
- void onTrustChanged(boolean enabled, int userId);
+ void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
/**
* Reports that whether trust is managed has changed
diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
index 0eb9d21..da992f5 100644
--- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
+++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java
@@ -124,8 +124,7 @@ public class BluetoothGattCallbackWrapper extends IBluetoothGattCallback.Stub {
}
@Override
- public void onFoundOrLost(boolean onFound, String address, int rssi, byte[] advData)
- throws RemoteException {
+ public void onFoundOrLost(boolean onFound, ScanResult scanResult) throws RemoteException {
}
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index edf823e..7070bae 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -21,6 +21,7 @@ import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
+import android.bluetooth.le.ResultStorageDescriptor;
import android.os.ParcelUuid;
import android.bluetooth.IBluetoothGattCallback;
@@ -34,7 +35,8 @@ interface IBluetoothGatt {
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
- in List<ScanFilter> filters);
+ in List<ScanFilter> filters,
+ in List scanStorages);
void stopScan(in int appIf, in boolean isServer);
void flushPendingBatchResults(in int appIf, in boolean isServer);
void startMultiAdvertising(in int appIf,
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index f14cce0..00b6b1b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -69,6 +69,5 @@ oneway interface IBluetoothGattCallback {
in AdvertiseSettings advertiseSettings);
void onConfigureMTU(in String address, in int mtu, in int status);
void onConnectionCongested(in String address, in boolean congested);
- void onFoundOrLost(in boolean onFound, in String address, in int rssi,
- in byte[] advData);
+ void onFoundOrLost(in boolean onFound, in ScanResult scanResult);
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 45e466f..7c3cbc6 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -16,20 +16,19 @@
package android.bluetooth.le;
+import android.annotation.SystemApi;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallbackWrapper;
import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothManager;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.util.Log;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -100,6 +99,11 @@ public final class BluetoothLeScanner {
*/
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
+ startScan(filters, settings, callback, null);
+ }
+
+ private void startScan(List<ScanFilter> filters, ScanSettings settings,
+ final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) {
checkAdapterState();
if (settings == null || callback == null) {
throw new IllegalArgumentException("settings or callback is null");
@@ -125,7 +129,7 @@ public final class BluetoothLeScanner {
return;
}
BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
- settings, callback);
+ settings, callback, resultStorages);
try {
UUID uuid = UUID.randomUUID();
gatt.registerClient(new ParcelUuid(uuid), wrapper);
@@ -155,7 +159,8 @@ public final class BluetoothLeScanner {
synchronized (mLeScanClients) {
BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
if (wrapper == null) {
- if (DBG) Log.d(TAG, "could not find callback wrapper");
+ if (DBG)
+ Log.d(TAG, "could not find callback wrapper");
return;
}
wrapper.stopLeScan();
@@ -185,6 +190,25 @@ public final class BluetoothLeScanner {
}
/**
+ * Start truncated scan.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
+ final ScanCallback callback) {
+ int filterSize = truncatedFilters.size();
+ List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
+ List<List<ResultStorageDescriptor>> scanStorages =
+ new ArrayList<List<ResultStorageDescriptor>>(filterSize);
+ for (TruncatedFilter filter : truncatedFilters) {
+ scanFilters.add(filter.getFilter());
+ scanStorages.add(filter.getStorageDescriptors());
+ }
+ startScan(scanFilters, settings, callback, scanStorages);
+ }
+
+ /**
* Bluetooth GATT interface callbacks
*/
private static class BleScanCallbackWrapper extends BluetoothGattCallbackWrapper {
@@ -194,6 +218,7 @@ public final class BluetoothLeScanner {
private final List<ScanFilter> mFilters;
private ScanSettings mSettings;
private IBluetoothGatt mBluetoothGatt;
+ private List<List<ResultStorageDescriptor>> mResultStorages;
// mLeHandle 0: not registered
// -1: scan stopped
@@ -202,12 +227,13 @@ public final class BluetoothLeScanner {
public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
List<ScanFilter> filters, ScanSettings settings,
- ScanCallback scanCallback) {
+ ScanCallback scanCallback, List<List<ResultStorageDescriptor>> resultStorages) {
mBluetoothGatt = bluetoothGatt;
mFilters = filters;
mSettings = settings;
mScanCallback = scanCallback;
mClientIf = 0;
+ mResultStorages = resultStorages;
}
public boolean scanStarted() {
@@ -272,7 +298,8 @@ public final class BluetoothLeScanner {
if (status == BluetoothGatt.GATT_SUCCESS) {
mClientIf = clientIf;
try {
- mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters);
+ mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters,
+ mResultStorages);
} catch (RemoteException e) {
Log.e(TAG, "fail to start le scan: " + e);
mClientIf = -1;
@@ -322,26 +349,34 @@ public final class BluetoothLeScanner {
}
@Override
- public void onFoundOrLost(boolean onFound, String address, int rssi,
- byte[] advData) {
+ public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) {
if (DBG) {
- Log.d(TAG, "onFoundOrLost() - Device=" + address);
+ Log.d(TAG, "onFoundOrLost() - onFound = " + onFound +
+ " " + scanResult.toString());
}
- // ToDo: Fix issue with underlying reporting from chipset
- BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
- address);
- long scanNanos = SystemClock.elapsedRealtimeNanos();
- ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(advData), rssi,
- scanNanos);
- if (onFound) {
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, result);
- } else {
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, result);
+
+ // Check null in case the scan has been stopped
+ synchronized (this) {
+ if (mClientIf <= 0)
+ return;
}
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (onFound) {
+ mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH,
+ scanResult);
+ } else {
+ mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST,
+ scanResult);
+ }
+ }
+ });
}
}
- //TODO: move this api to a common util class.
+ // TODO: move this api to a common util class.
private void checkAdapterState() {
if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
throw new IllegalStateException("BT Adapter is not turned ON");
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.aidl b/core/java/android/bluetooth/le/ResultStorageDescriptor.aidl
new file mode 100644
index 0000000..f218a01
--- /dev/null
+++ b/core/java/android/bluetooth/le/ResultStorageDescriptor.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.bluetooth.le;
+
+/**
+ * {@hide}
+ */
+
+parcelable ResultStorageDescriptor;
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.java b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
new file mode 100644
index 0000000..748f97d
--- /dev/null
+++ b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
@@ -0,0 +1,93 @@
+/*
+ * 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.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the way to store scan result.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ResultStorageDescriptor implements Parcelable {
+ private int mType;
+ private int mOffset;
+ private int mLength;
+
+ public int getType() {
+ return mType;
+ }
+
+ public int getOffset() {
+ return mOffset;
+ }
+
+ public int getLength() {
+ return mLength;
+ }
+
+ /**
+ * Constructor of {@link ResultStorageDescriptor}
+ *
+ * @param type Type of the data.
+ * @param offset Offset from start of the advertise packet payload.
+ * @param length Byte length of the data
+ */
+ public ResultStorageDescriptor(int type, int offset, int length) {
+ mType = type;
+ mOffset = offset;
+ mLength = length;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mType);
+ dest.writeInt(mOffset);
+ dest.writeInt(mLength);
+ }
+
+ private ResultStorageDescriptor(Parcel in) {
+ ReadFromParcel(in);
+ }
+
+ private void ReadFromParcel(Parcel in) {
+ mType = in.readInt();
+ mOffset = in.readInt();
+ mLength = in.readInt();
+ }
+
+ public static final Parcelable.Creator<ResultStorageDescriptor>
+ CREATOR = new Creator<ResultStorageDescriptor>() {
+ @Override
+ public ResultStorageDescriptor createFromParcel(Parcel source) {
+ return new ResultStorageDescriptor(source);
+ }
+
+ @Override
+ public ResultStorageDescriptor[] newArray(int size) {
+ return new ResultStorageDescriptor[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
new file mode 100644
index 0000000..6a6b3e3
--- /dev/null
+++ b/core/java/android/bluetooth/le/TruncatedFilter.java
@@ -0,0 +1,61 @@
+/*
+ * 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.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * A special scan filter that lets the client decide how the scan record should be stored.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TruncatedFilter {
+ private final ScanFilter mFilter;
+ private final List<ResultStorageDescriptor> mStorageDescriptors;
+
+ /**
+ * Constructor for {@link TruncatedFilter}.
+ *
+ * @param filter Scan filter of the truncated filter.
+ * @param storageDescriptors Describes how the scan should be stored.
+ */
+ public TruncatedFilter(ScanFilter filter, List<ResultStorageDescriptor> storageDescriptors) {
+ mFilter = filter;
+ mStorageDescriptors = storageDescriptors;
+ }
+
+ /**
+ * Returns the scan filter.
+ */
+ public ScanFilter getFilter() {
+ return mFilter;
+ }
+
+ /**
+ * Returns a list of descriptor for scan result storage.
+ */
+ public List<ResultStorageDescriptor> getStorageDescriptors() {
+ return mStorageDescriptors;
+ }
+
+
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 87d14b9..0ca800f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -329,7 +329,7 @@ public abstract class ContentResolver {
try {
String type = ActivityManagerNative.getDefault().getProviderMimeType(
- url, UserHandle.myUserId());
+ ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
return type;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7417208..5f046c5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2616,6 +2616,7 @@ public abstract class Context {
*
* @see #getSystemService
*/
+ @SystemApi
public static final String BACKUP_SERVICE = "backup";
/**
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 176a81c..5223476 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -21,7 +21,6 @@ import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
import android.content.pm.InstallSessionInfo;
import android.content.pm.InstallSessionParams;
-import android.os.ParcelFileDescriptor;
/** {@hide} */
interface IPackageInstaller {
@@ -37,4 +36,6 @@ interface IPackageInstaller {
void uninstall(String packageName, int flags, in IPackageDeleteObserver2 observer, int userId);
void uninstallSplit(String packageName, String splitName, int flags, in IPackageDeleteObserver2 observer, int userId);
+
+ void setPermissionsResult(int sessionId, boolean accepted);
}
diff --git a/core/java/android/content/pm/InstallSessionInfo.java b/core/java/android/content/pm/InstallSessionInfo.java
index f263885..161bcde 100644
--- a/core/java/android/content/pm/InstallSessionInfo.java
+++ b/core/java/android/content/pm/InstallSessionInfo.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -33,8 +32,12 @@ public class InstallSessionInfo implements Parcelable {
/** {@hide} */
public String installerPackageName;
/** {@hide} */
+ public String resolvedBaseCodePath;
+ /** {@hide} */
public float progress;
/** {@hide} */
+ public boolean sealed;
+ /** {@hide} */
public boolean open;
/** {@hide} */
@@ -56,7 +59,9 @@ public class InstallSessionInfo implements Parcelable {
public InstallSessionInfo(Parcel source) {
sessionId = source.readInt();
installerPackageName = source.readString();
+ resolvedBaseCodePath = source.readString();
progress = source.readFloat();
+ sealed = source.readInt() != 0;
open = source.readInt() != 0;
mode = source.readInt();
@@ -149,7 +154,9 @@ public class InstallSessionInfo implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(sessionId);
dest.writeString(installerPackageName);
+ dest.writeString(resolvedBaseCodePath);
dest.writeFloat(progress);
+ dest.writeInt(sealed ? 1 : 0);
dest.writeInt(open ? 1 : 0);
dest.writeInt(mode);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8c37e9e..268919c 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -210,20 +210,6 @@ public class LauncherApps {
* Starts an activity in the specified profile.
*
* @param component The ComponentName of the activity to launch
- * @param sourceBounds The Rect containing the source bounds of the clicked icon
- * @param opts Options to pass to startActivity
- * @param user The UserHandle of the profile
- * @hide remove before ship
- */
- public void startActivityForProfile(ComponentName component, Rect sourceBounds,
- Bundle opts, UserHandle user) {
- startActivityForProfile(component, user, sourceBounds, opts);
- }
-
- /**
- * Starts an activity in the specified profile.
- *
- * @param component The ComponentName of the activity to launch
* @param user The UserHandle of the profile
* @param sourceBounds The Rect containing the source bounds of the clicked icon
* @param opts Options to pass to startActivity
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 01c080d..d70e22c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -81,6 +81,10 @@ public class PackageInstaller {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ /** {@hide} */
+ public static final String
+ ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
+
/**
* An integer session ID.
*
@@ -88,6 +92,9 @@ public class PackageInstaller {
*/
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
+ /** {@hide} */
+ public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
+
private final PackageManager mPm;
private final IPackageInstaller mInstaller;
private final int mUserId;
@@ -206,6 +213,15 @@ public class PackageInstaller {
}
}
+ /** {@hide} */
+ public void setPermissionsResult(int sessionId, boolean accepted) {
+ try {
+ mInstaller.setPermissionsResult(sessionId, accepted);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
/**
* Events for observing session lifecycle.
* <p>
@@ -541,6 +557,26 @@ public class PackageInstaller {
*/
public static abstract class UninstallCallback {
/**
+ * Generic unknown failure. The system will always try to provide a more
+ * specific failure reason, but in some rare cases this may be
+ * delivered.
+ */
+ public static final int FAILURE_UNKNOWN = 0;
+
+ /**
+ * This uninstall was blocked. The package may be required for core
+ * system operation, or the user may be restricted. Attempting to
+ * uninstall again will have the same result.
+ */
+ public static final int FAILURE_BLOCKED = 1;
+
+ /**
+ * This uninstall was actively aborted. For example, the user declined
+ * to uninstall. You may try to uninstall again.
+ */
+ public static final int FAILURE_ABORTED = 2;
+
+ /**
* User action is required to proceed. You can start the given intent
* activity to involve the user and continue.
* <p>
@@ -551,7 +587,7 @@ public class PackageInstaller {
public abstract void onUserActionRequired(Intent intent);
public abstract void onSuccess();
- public abstract void onFailure(String msg);
+ public abstract void onFailure(int failureReason, String msg, Bundle extras);
}
/** {@hide} */
@@ -572,8 +608,9 @@ public class PackageInstaller {
if (returnCode == PackageManager.DELETE_SUCCEEDED) {
target.onSuccess();
} else {
+ final int failureReason = PackageManager.deleteStatusToFailureReason(returnCode);
msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg;
- target.onFailure(msg);
+ target.onFailure(failureReason, msg, null);
}
}
}
@@ -603,9 +640,8 @@ public class PackageInstaller {
* permission, incompatible certificates, etc. The user may be able to
* uninstall another app to fix the issue.
* <p>
- * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} if one
- * specific package was identified as the cause of the conflict. If
- * unknown, or multiple packages, the extra may be {@code null}.
+ * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} with the
+ * specific packages identified as the cause of the conflict.
*/
public static final int FAILURE_CONFLICT = 2;
@@ -626,6 +662,15 @@ public class PackageInstaller {
*/
public static final int FAILURE_INCOMPATIBLE = 4;
+ /**
+ * This install session failed because it was actively aborted. For
+ * example, the user declined requested permissions, or a verifier
+ * rejected the session.
+ *
+ * @see PackageManager#VERIFICATION_REJECT
+ */
+ public static final int FAILURE_ABORTED = 5;
+
public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1e4ed31..b957a15 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageInstaller.CommitCallback;
+import android.content.pm.PackageInstaller.UninstallCallback;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -35,6 +37,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
@@ -770,6 +773,9 @@ public abstract class PackageManager {
*/
public static final int NO_NATIVE_LIBRARIES = -114;
+ /** {@hide} */
+ public static final int INSTALL_FAILED_ABORTED = -115;
+
/**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
@@ -842,7 +848,10 @@ public abstract class PackageManager {
*
* @hide
*/
- public static final int DELETE_FAILED_OWNER_BLOCKED= -4;
+ public static final int DELETE_FAILED_OWNER_BLOCKED = -4;
+
+ /** {@hide} */
+ public static final int DELETE_FAILED_ABORTED = -5;
/**
* Return code that is passed to the {@link IPackageMoveObserver} by
@@ -3830,6 +3839,7 @@ public abstract class PackageManager {
case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED";
case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";
case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";
+ case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
default: return Integer.toString(status);
}
}
@@ -3857,8 +3867,8 @@ public abstract class PackageManager {
case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE;
case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE;
case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE;
- case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_UNKNOWN;
- case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_UNKNOWN;
+ case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_ABORTED;
+ case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_ABORTED;
case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID;
case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID;
case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID;
@@ -3876,6 +3886,7 @@ public abstract class PackageManager {
case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE;
case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT;
case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE;
+ case INSTALL_FAILED_ABORTED: return CommitCallback.FAILURE_ABORTED;
default: return CommitCallback.FAILURE_UNKNOWN;
}
}
@@ -3888,7 +3899,57 @@ public abstract class PackageManager {
case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER";
case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED";
case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
+ case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED";
default: return Integer.toString(status);
}
}
+
+ /** {@hide} */
+ public static int deleteStatusToFailureReason(int status) {
+ switch (status) {
+ case DELETE_FAILED_INTERNAL_ERROR: return UninstallCallback.FAILURE_UNKNOWN;
+ case DELETE_FAILED_DEVICE_POLICY_MANAGER: return UninstallCallback.FAILURE_BLOCKED;
+ case DELETE_FAILED_USER_RESTRICTED: return UninstallCallback.FAILURE_BLOCKED;
+ case DELETE_FAILED_OWNER_BLOCKED: return UninstallCallback.FAILURE_BLOCKED;
+ case DELETE_FAILED_ABORTED: return UninstallCallback.FAILURE_ABORTED;
+ default: return UninstallCallback.FAILURE_UNKNOWN;
+ }
+ }
+
+ /** {@hide} */
+ public static class LegacyPackageInstallObserver extends PackageInstallObserver {
+ private final IPackageInstallObserver mLegacy;
+
+ public LegacyPackageInstallObserver(IPackageInstallObserver legacy) {
+ mLegacy = legacy;
+ }
+
+ @Override
+ public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+ Bundle extras) {
+ if (mLegacy == null) return;
+ try {
+ mLegacy.packageInstalled(basePackageName, returnCode);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** {@hide} */
+ public static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
+ private final IPackageDeleteObserver mLegacy;
+
+ public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
+ mLegacy = legacy;
+ }
+
+ @Override
+ public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+ if (mLegacy == null) return;
+ try {
+ mLegacy.packageDeleted(basePackageName, returnCode);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 900b41d..3c290f7 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -233,7 +233,7 @@ public class ColorStateList implements Parcelable {
}
if (alphaRes != 0) {
- alpha = r.getFraction(alphaRes, 1, 1);
+ alpha = r.getFloat(alphaRes);
}
// Apply alpha modulation.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 5face69..52d1c79 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -986,6 +986,34 @@ public class Resources {
}
/**
+ * Retrieve a floating-point value for a particular resource ID.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ *
+ * @return Returns the floating-point value contained in the resource.
+ *
+ * @throws NotFoundException Throws NotFoundException if the given ID does
+ * not exist or is not a floating-point value.
+ * @hide Pending API council approval.
+ */
+ public float getFloat(int id) {
+ synchronized (mAccessLock) {
+ TypedValue value = mTmpValue;
+ if (value == null) {
+ mTmpValue = value = new TypedValue();
+ }
+ getValue(id, value, true);
+ if (value.type == TypedValue.TYPE_FLOAT) {
+ return value.getFloat();
+ }
+ throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ + Integer.toHexString(value.type) + " is not valid");
+ }
+ }
+
+ /**
* Return an XmlResourceParser through which you can read a view layout
* description for the given resource ID. This parser has limited
* functionality -- in particular, you can't change its input, and only
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index c461511..6a9d565 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -130,15 +130,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract String getId();
/**
- * <p>Set up a new output set of Surfaces for the camera device.</p>
- *
- * @deprecated Use {@link #createCaptureSession} instead
- * @hide
- */
- @Deprecated
- public abstract void configureOutputs(List<Surface> outputs) throws CameraAccessException;
-
- /**
* <p>Create a new camera capture session by providing the target output set of Surfaces to the
* camera device.</p>
*
@@ -276,68 +267,6 @@ public abstract class CameraDevice implements AutoCloseable {
throws CameraAccessException;
/**
- * <p>Submit a request for an image to be captured by this CameraDevice.</p>
- *
- * @deprecated Use {@link CameraCaptureSession#capture} instead
- * @hide
- */
- @Deprecated
- public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler)
- throws CameraAccessException;
-
- /**
- * Submit a list of requests to be captured in sequence as a burst.
- *
- * @deprecated Use {@link CameraCaptureSession#captureBurst} instead
- * @hide
- */
- @Deprecated
- public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * Request endlessly repeating capture of images by this CameraDevice.
- *
- * @deprecated Use {@link CameraCaptureSession#setRepeatingRequest} instead
- * @hide
- */
- @Deprecated
- public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * <p>Request endlessly repeating capture of a sequence of images by this
- * CameraDevice.</p>
- *
- * @deprecated Use {@link CameraCaptureSession#setRepeatingBurst} instead
- * @hide
- */
- @Deprecated
- public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * <p>Cancel any ongoing repeating capture set by either
- * {@link #setRepeatingRequest setRepeatingRequest} or
- * {@link #setRepeatingBurst}.
- *
- * @deprecated Use {@link CameraCaptureSession#stopRepeating} instead
- * @hide
- */
- @Deprecated
- public abstract void stopRepeating() throws CameraAccessException;
-
- /**
- * Flush all captures currently pending and in-progress as fast as
- * possible.
- *
- * @deprecated Use {@link CameraCaptureSession#abortCaptures} instead
- * @hide
- */
- @Deprecated
- public abstract void flush() throws CameraAccessException;
-
- /**
* Close the connection to this camera device as quickly as possible.
*
* <p>Immediately after this call, all calls to the camera device or active session interface
@@ -356,96 +285,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void close();
/**
- * <p>A listener for tracking the progress of a {@link CaptureRequest}
- * submitted to the camera device.</p>
- *
- * @deprecated Use {@link CameraCaptureSession.CaptureListener} instead
- * @hide
- */
- @Deprecated
- public static abstract class CaptureListener {
-
- /**
- * This constant is used to indicate that no images were captured for
- * the request.
- *
- * @hide
- */
- public static final int NO_FRAMES_CAPTURED = -1;
-
- /**
- * This method is called when the camera device has started capturing
- * the output image for the request, at the beginning of image exposure.
- *
- * @see android.media.MediaActionSound
- */
- public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp) {
- // default empty implementation
- }
-
- /**
- * This method is called when some results from an image capture are
- * available.
- *
- * @hide
- */
- public void onCapturePartial(CameraDevice camera,
- CaptureRequest request, CaptureResult result) {
- // default empty implementation
- }
-
- /**
- * This method is called when an image capture makes partial forward progress; some
- * (but not all) results from an image capture are available.
- *
- */
- public void onCaptureProgressed(CameraDevice camera,
- CaptureRequest request, CaptureResult partialResult) {
- // default empty implementation
- }
-
- /**
- * This method is called when an image capture has fully completed and all the
- * result metadata is available.
- */
- public void onCaptureCompleted(CameraDevice camera,
- CaptureRequest request, TotalCaptureResult result) {
- // default empty implementation
- }
-
- /**
- * This method is called instead of {@link #onCaptureCompleted} when the
- * camera device failed to produce a {@link CaptureResult} for the
- * request.
- */
- public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request, CaptureFailure failure) {
- // default empty implementation
- }
-
- /**
- * This method is called independently of the others in CaptureListener,
- * when a capture sequence finishes and all {@link CaptureResult}
- * or {@link CaptureFailure} for it have been returned via this listener.
- */
- public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, long frameNumber) {
- // default empty implementation
- }
-
- /**
- * This method is called independently of the others in CaptureListener,
- * when a capture sequence aborts before any {@link CaptureResult}
- * or {@link CaptureFailure} for it have been returned via this listener.
- */
- public void onCaptureSequenceAborted(CameraDevice camera,
- int sequenceId) {
- // default empty implementation
- }
- }
-
- /**
* A listener for notifications about the state of a camera
* device.
*
@@ -542,40 +381,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void onOpened(CameraDevice camera); // Must implement
/**
- * The method called when a camera device has no outputs configured.
- *
- * @deprecated Use {@link #onOpened} instead.
- * @hide
- */
- @Deprecated
- public void onUnconfigured(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
- * The method called when a camera device begins processing
- * {@link CaptureRequest capture requests}.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onActive} instead.
- * @hide
- */
- @Deprecated
- public void onActive(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
- * The method called when a camera device is busy.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onConfigured} instead.
- * @hide
- */
- @Deprecated
- public void onBusy(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
* The method called when a camera device has been closed with
* {@link CameraDevice#close}.
*
@@ -591,18 +396,6 @@ public abstract class CameraDevice implements AutoCloseable {
}
/**
- * The method called when a camera device has finished processing all
- * submitted capture requests and has reached an idle state.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onReady} instead.
- * @hide
- */
- @Deprecated
- public void onIdle(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
* The method called when a camera device is no longer available for
* use.
*
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index f829f5e..a15028c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -103,7 +103,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* Use the same handler as the device's StateListener for all the internal coming events
*
* This ensures total ordering between CameraDevice.StateListener and
- * CameraDevice.CaptureListener events.
+ * CameraDeviceImpl.CaptureListener events.
*/
mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
/*name*/"seq");
@@ -141,7 +141,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
Log.v(TAG, "capture - request " + request + ", listener " + listener + " handler" +
@@ -164,7 +164,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -186,7 +186,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
Log.v(TAG, "setRepeatingRequest - request " + request + ", listener " + listener +
@@ -209,7 +209,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -261,9 +261,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* <p>The semantics are identical to {@link #close}, except that unconfiguring will be skipped.
* <p>
*
+ * <p>After this call completes, the session will not call any further methods on the camera
+ * device.</p>
+ *
* @see CameraCaptureSession#close
*/
- synchronized void replaceSessionClose(CameraCaptureSession other) {
+ synchronized void replaceSessionClose() {
/*
* In order for creating new sessions to be fast, the new session should be created
* before the old session is closed.
@@ -278,13 +281,17 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
if (VERBOSE) Log.v(TAG, "replaceSessionClose");
- // #close was already called explicitly, keep going the slow route
- if (mClosed) {
- if (VERBOSE) Log.v(TAG, "replaceSessionClose - close was already called");
- return;
- }
-
+ // Set up fast shutdown. Possible alternative paths:
+ // - This session is active, so close() below starts the shutdown drain
+ // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
+ // - This session is already closed and has executed the idle drain listener, and
+ // configureOutputs(null) has already been called.
+ //
+ // Do not call configureOutputs(null) going forward, since it would race with the
+ // configuration for the new session. If it was already called, then we don't care, since it
+ // won't get called again.
mSkipUnconfigure = true;
+
close();
}
@@ -347,7 +354,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
/**
* Forward callbacks from
- * CameraDevice.CaptureListener to the CameraCaptureSession.CaptureListener.
+ * CameraDeviceImpl.CaptureListener to the CameraCaptureSession.CaptureListener.
*
* <p>In particular, all calls are automatically split to go both to our own
* internal listener, and to the user-specified listener (by transparently posting
@@ -356,9 +363,9 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* <p>When a capture sequence finishes, update the pending checked sequences set.</p>
*/
@SuppressWarnings("deprecation")
- private CameraDevice.CaptureListener createCaptureListenerProxy(
+ private CameraDeviceImpl.CaptureListener createCaptureListenerProxy(
Handler handler, CaptureListener listener) {
- CameraDevice.CaptureListener localListener = new CameraDevice.CaptureListener() {
+ CameraDeviceImpl.CaptureListener localListener = new CameraDeviceImpl.CaptureListener() {
@Override
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
@@ -379,27 +386,30 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* - then forward the call to a handler
* - then finally invoke the destination method on the session listener object
*/
- Dispatchable<CaptureListener> userListenerSink;
- if (listener == null) { // OK: API allows the user to not specify a listener
- userListenerSink = new NullDispatcher<>();
- } else {
- userListenerSink = new InvokeDispatcher<>(listener);
+ if (listener == null) {
+ // OK: API allows the user to not specify a listener, and the handler may
+ // also be null in that case. Collapse whole dispatch chain to only call the local
+ // listener
+ return localListener;
}
- InvokeDispatcher<CameraDevice.CaptureListener> localSink =
+ InvokeDispatcher<CameraDeviceImpl.CaptureListener> localSink =
new InvokeDispatcher<>(localListener);
+
+ InvokeDispatcher<CaptureListener> userListenerSink =
+ new InvokeDispatcher<>(listener);
HandlerDispatcher<CaptureListener> handlerPassthrough =
new HandlerDispatcher<>(userListenerSink, handler);
- DuckTypingDispatcher<CameraDevice.CaptureListener, CaptureListener> duckToSession
+ DuckTypingDispatcher<CameraDeviceImpl.CaptureListener, CaptureListener> duckToSession
= new DuckTypingDispatcher<>(handlerPassthrough, CaptureListener.class);
- ArgumentReplacingDispatcher<CameraDevice.CaptureListener, CameraCaptureSessionImpl>
- replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
- /*argumentIndex*/0, this);
+ ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureListener, CameraCaptureSessionImpl>
+ replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
+ /*argumentIndex*/0, this);
- BroadcastDispatcher<CameraDevice.CaptureListener> broadcaster =
- new BroadcastDispatcher<CameraDevice.CaptureListener>(
- replaceDeviceWithSession,
- localSink);
+ BroadcastDispatcher<CameraDeviceImpl.CaptureListener> broadcaster =
+ new BroadcastDispatcher<CameraDeviceImpl.CaptureListener>(
+ replaceDeviceWithSession,
+ localSink);
return new ListenerProxies.DeviceCaptureListenerProxy(broadcaster);
}
@@ -415,10 +425,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* </ul>
* </p>
* */
- CameraDevice.StateListener getDeviceStateListener() {
+ CameraDeviceImpl.StateListenerKK getDeviceStateListener() {
final CameraCaptureSession session = this;
- return new CameraDevice.StateListener() {
+ return new CameraDeviceImpl.StateListenerKK() {
private boolean mBusy = false;
private boolean mActive = false;
@@ -596,6 +606,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
*
* This operation is idempotent; a session will not be closed twice.
*/
+ if (VERBOSE) Log.v(TAG, "Session drain complete, skip unconfigure: " +
+ mSkipUnconfigure);
// Fast path: A new capture session has replaced this one; don't unconfigure.
if (mSkipUnconfigure) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 18b1202..71eb0e9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -21,8 +21,10 @@ import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.TotalCaptureResult;
@@ -47,7 +49,7 @@ import java.util.TreeSet;
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
*/
-public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
+public class CameraDeviceImpl extends CameraDevice {
private final String TAG;
private final boolean DEBUG;
@@ -62,7 +64,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
private final StateListener mDeviceListener;
- private volatile StateListener mSessionStateListener;
+ private volatile StateListenerKK mSessionStateListener;
private final Handler mDeviceHandler;
private volatile boolean mClosing = false;
@@ -103,7 +105,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnOpened = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -119,7 +121,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnUnconfigured = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -128,14 +130,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onUnconfigured(CameraDeviceImpl.this);
}
- mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnActive = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -144,14 +145,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onActive(CameraDeviceImpl.this);
}
- mDeviceListener.onActive(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnBusy = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -160,7 +160,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onBusy(CameraDeviceImpl.this);
}
- mDeviceListener.onBusy(CameraDeviceImpl.this);
}
};
@@ -172,7 +171,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (mClosedOnce) {
throw new AssertionError("Don't post #onClosed more than once");
}
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
sessionListener = mSessionStateListener;
}
@@ -187,7 +186,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnIdle = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -196,14 +195,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onIdle(CameraDeviceImpl.this);
}
- mDeviceListener.onIdle(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnDisconnected = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -313,7 +311,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return mCameraId;
}
- @Override
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
@@ -390,7 +387,11 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
checkIfCameraClosedOrInError();
- // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
+ // Notify current session that it's going away, before starting camera operations
+ // After this call completes, the session is not allowed to call into CameraDeviceImpl
+ if (mCurrentSession != null) {
+ mCurrentSession.replaceSessionClose();
+ }
// TODO: dont block for this
boolean configureSuccess = true;
@@ -410,10 +411,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
configureSuccess);
- if (mCurrentSession != null) {
- mCurrentSession.replaceSessionClose(newSession);
- }
-
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
@@ -425,6 +422,15 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ /**
+ * For use by backwards-compatibility code only.
+ */
+ public void setSessionListener(StateListenerKK sessionListener) {
+ synchronized(mInterfaceLock) {
+ mSessionStateListener = sessionListener;
+ }
+ }
+
@Override
public CaptureRequest.Builder createCaptureRequest(int templateType)
throws CameraAccessException {
@@ -449,7 +455,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException {
if (DEBUG) {
@@ -460,7 +465,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
}
- @Override
public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -543,9 +547,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
// Need a valid handler, or current thread needs to have a looper, if
// listener is valid
- if (listener != null) {
- handler = checkHandler(handler);
- }
+ handler = checkHandler(handler, listener);
// Make sure that there all requests have at least 1 surface; all surfaces are non-null
for (CaptureRequest request : requestList) {
@@ -613,7 +615,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Handler handler) throws CameraAccessException {
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
@@ -621,7 +622,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
}
- @Override
public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -630,7 +630,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
}
- @Override
public void stopRepeating() throws CameraAccessException {
synchronized(mInterfaceLock) {
@@ -681,7 +680,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public void flush() throws CameraAccessException {
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
@@ -739,6 +737,133 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ /**
+ * <p>A listener for tracking the progress of a {@link CaptureRequest}
+ * submitted to the camera device.</p>
+ *
+ */
+ public static abstract class CaptureListener {
+
+ /**
+ * This constant is used to indicate that no images were captured for
+ * the request.
+ *
+ * @hide
+ */
+ public static final int NO_FRAMES_CAPTURED = -1;
+
+ /**
+ * This method is called when the camera device has started capturing
+ * the output image for the request, at the beginning of image exposure.
+ *
+ * @see android.media.MediaActionSound
+ */
+ public void onCaptureStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when some results from an image capture are
+ * available.
+ *
+ * @hide
+ */
+ public void onCapturePartial(CameraDevice camera,
+ CaptureRequest request, CaptureResult result) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when an image capture makes partial forward progress; some
+ * (but not all) results from an image capture are available.
+ *
+ */
+ public void onCaptureProgressed(CameraDevice camera,
+ CaptureRequest request, CaptureResult partialResult) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when an image capture has fully completed and all the
+ * result metadata is available.
+ */
+ public void onCaptureCompleted(CameraDevice camera,
+ CaptureRequest request, TotalCaptureResult result) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called instead of {@link #onCaptureCompleted} when the
+ * camera device failed to produce a {@link CaptureResult} for the
+ * request.
+ */
+ public void onCaptureFailed(CameraDevice camera,
+ CaptureRequest request, CaptureFailure failure) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called independently of the others in CaptureListener,
+ * when a capture sequence finishes and all {@link CaptureResult}
+ * or {@link CaptureFailure} for it have been returned via this listener.
+ */
+ public void onCaptureSequenceCompleted(CameraDevice camera,
+ int sequenceId, long frameNumber) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called independently of the others in CaptureListener,
+ * when a capture sequence aborts before any {@link CaptureResult}
+ * or {@link CaptureFailure} for it have been returned via this listener.
+ */
+ public void onCaptureSequenceAborted(CameraDevice camera,
+ int sequenceId) {
+ // default empty implementation
+ }
+ }
+
+ /**
+ * A listener for notifications about the state of a camera device, adding in the callbacks that
+ * were part of the earlier KK API design, but now only used internally.
+ */
+ public static abstract class StateListenerKK extends StateListener {
+ /**
+ * The method called when a camera device has no outputs configured.
+ *
+ */
+ public void onUnconfigured(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device begins processing
+ * {@link CaptureRequest capture requests}.
+ *
+ */
+ public void onActive(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device is busy.
+ *
+ */
+ public void onBusy(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device has finished processing all
+ * submitted capture requests and has reached an idle state.
+ *
+ */
+ public void onIdle(CameraDevice camera) {
+ // Default empty implementation
+ }
+ }
+
static class CaptureListenerHolder {
private final boolean mRepeating;
@@ -1155,6 +1280,18 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return handler;
}
+ /**
+ * Default handler management, conditional on there being a listener.
+ *
+ * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
+ */
+ static <T> Handler checkHandler(Handler handler, T listener) {
+ if (listener != null) {
+ return checkHandler(handler);
+ }
+ return handler;
+ }
+
private void checkIfCameraClosedOrInError() throws CameraAccessException {
if (mInError) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index dc71a06..febb015 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -67,6 +67,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -227,6 +228,7 @@ public class CameraMetadataNative implements Parcelable {
private static final String CELLID_PROCESS = "CELLID";
private static final String GPS_PROCESS = "GPS";
+ private static final int FACE_LANDMARK_SIZE = 6;
private static String translateLocationProviderToProcess(final String provider) {
if (provider == null) {
@@ -347,7 +349,7 @@ public class CameraMetadataNative implements Parcelable {
// Check if key has been overridden to use a wrapper class on the java side.
GetCommand g = sGetCommandMap.get(key);
if (g != null) {
- return (T) g.getValue(this, key);
+ return g.getValue(this, key);
}
return getBase(key);
}
@@ -587,9 +589,71 @@ public class CameraMetadataNative implements Parcelable {
return availableFormats;
}
- private Face[] getFaces() {
- final int FACE_LANDMARK_SIZE = 6;
+ private boolean setFaces(Face[] faces) {
+ if (faces == null) {
+ return false;
+ }
+
+ int numFaces = faces.length;
+
+ // Detect if all faces are SIMPLE or not; count # of valid faces
+ boolean fullMode = true;
+ for (Face face : faces) {
+ if (face == null) {
+ numFaces--;
+ Log.w(TAG, "setFaces - null face detected, skipping");
+ continue;
+ }
+
+ if (face.getId() == Face.ID_UNSUPPORTED) {
+ fullMode = false;
+ }
+ }
+
+ Rect[] faceRectangles = new Rect[numFaces];
+ byte[] faceScores = new byte[numFaces];
+ int[] faceIds = null;
+ int[] faceLandmarks = null;
+
+ if (fullMode) {
+ faceIds = new int[numFaces];
+ faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
+ }
+
+ int i = 0;
+ for (Face face : faces) {
+ if (face == null) {
+ continue;
+ }
+
+ faceRectangles[i] = face.getBounds();
+ faceScores[i] = (byte)face.getScore();
+
+ if (fullMode) {
+ faceIds[i] = face.getId();
+ int j = 0;
+
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
+ }
+
+ i++;
+ }
+
+ set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
+ set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
+ set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
+ set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
+
+ return true;
+ }
+
+ private Face[] getFaces() {
Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
if (faceDetectMode == null) {
Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
@@ -653,9 +717,12 @@ public class CameraMetadataNative implements Parcelable {
if (faceScores[i] <= Face.SCORE_MAX &&
faceScores[i] >= Face.SCORE_MIN &&
faceIds[i] >= 0) {
- Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]);
- Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]);
- Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]);
+ Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
+ Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
+ Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
leftEye, rightEye, mouth);
faceList.add(face);
@@ -865,6 +932,13 @@ public class CameraMetadataNative implements Parcelable {
metadata.setFaceRectangles((Rect[]) value);
}
});
+ sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setFaces((Face[])value);
+ }
+ });
sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
@Override
public <T> void setValue(CameraMetadataNative metadata, T value) {
diff --git a/core/java/android/hardware/camera2/impl/ListenerProxies.java b/core/java/android/hardware/camera2/impl/ListenerProxies.java
index ab9a4d5..f44f9ad 100644
--- a/core/java/android/hardware/camera2/impl/ListenerProxies.java
+++ b/core/java/android/hardware/camera2/impl/ListenerProxies.java
@@ -36,13 +36,13 @@ public class ListenerProxies {
// TODO: replace with codegen
- public static class DeviceStateListenerProxy extends CameraDevice.StateListener {
- private final MethodNameInvoker<CameraDevice.StateListener> mProxy;
+ public static class DeviceStateListenerProxy extends CameraDeviceImpl.StateListenerKK {
+ private final MethodNameInvoker<CameraDeviceImpl.StateListenerKK> mProxy;
public DeviceStateListenerProxy(
- Dispatchable<CameraDevice.StateListener> dispatchTarget) {
+ Dispatchable<CameraDeviceImpl.StateListenerKK> dispatchTarget) {
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.StateListener.class);
+ mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateListenerKK.class);
}
@Override
@@ -87,13 +87,13 @@ public class ListenerProxies {
}
@SuppressWarnings("deprecation")
- public static class DeviceCaptureListenerProxy extends CameraDevice.CaptureListener {
- private final MethodNameInvoker<CameraDevice.CaptureListener> mProxy;
+ public static class DeviceCaptureListenerProxy extends CameraDeviceImpl.CaptureListener {
+ private final MethodNameInvoker<CameraDeviceImpl.CaptureListener> mProxy;
public DeviceCaptureListenerProxy(
- Dispatchable<CameraDevice.CaptureListener> dispatchTarget) {
+ Dispatchable<CameraDeviceImpl.CaptureListener> dispatchTarget) {
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.CaptureListener.class);
+ mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureListener.class);
}
@Override
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
new file mode 100644
index 0000000..1470b70
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
@@ -0,0 +1,231 @@
+/*
+ * 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.camera2.legacy;
+
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.hardware.Camera.FaceDetectionListener;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.utils.ListUtils;
+import android.hardware.camera2.utils.ParamsUtils;
+import android.util.Log;
+import android.util.Size;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.hardware.camera2.CaptureRequest.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Map legacy face detect callbacks into face detection results.
+ */
+@SuppressWarnings("deprecation")
+public class LegacyFaceDetectMapper {
+ private static String TAG = "LegacyFaceDetectMapper";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private final Camera mCamera;
+ private final boolean mFaceDetectSupported;
+ private boolean mFaceDetectEnabled = false;
+
+ private final Object mLock = new Object();
+ private Camera.Face[] mFaces;
+ private Camera.Face[] mFacesPrev;
+ /**
+ * Instantiate a new face detect mapper.
+ *
+ * @param camera a non-{@code null} camera1 device
+ * @param characteristics a non-{@code null} camera characteristics for that camera1
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public LegacyFaceDetectMapper(Camera camera, CameraCharacteristics characteristics) {
+ mCamera = checkNotNull(camera, "camera must not be null");
+ checkNotNull(characteristics, "characteristics must not be null");
+
+ mFaceDetectSupported = ArrayUtils.contains(
+ characteristics.get(
+ CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES),
+ STATISTICS_FACE_DETECT_MODE_SIMPLE);
+
+ if (!mFaceDetectSupported) {
+ return;
+ }
+
+ mCamera.setFaceDetectionListener(new FaceDetectionListener() {
+
+ @Override
+ public void onFaceDetection(Camera.Face[] faces, Camera camera) {
+ int lengthFaces = faces == null ? 0 : faces.length;
+ synchronized (mLock) {
+ if (mFaceDetectEnabled) {
+ mFaces = faces;
+ } else if (lengthFaces > 0) {
+ // stopFaceDetectMode could race against the requests, print a debug log
+ Log.d(TAG,
+ "onFaceDetection - Ignored some incoming faces since" +
+ "face detection was disabled");
+ }
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces");
+ }
+ }
+ });
+ }
+
+ /**
+ * Process the face detect mode from the capture request into an api1 face detect toggle.
+ *
+ * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
+ * with the request.</p>
+ *
+ * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
+ * will have the latest faces detected as reflected by the camera1 callbacks.</p>
+ *
+ * <p>None of the arguments will be mutated.</p>
+ *
+ * @param captureRequest a non-{@code null} request
+ * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
+ */
+ public void processFaceDetectMode(CaptureRequest captureRequest,
+ Camera.Parameters parameters) {
+ checkNotNull(captureRequest, "captureRequest must not be null");
+
+ /*
+ * statistics.faceDetectMode
+ */
+ int fdMode = ParamsUtils.getOrDefault(captureRequest, STATISTICS_FACE_DETECT_MODE,
+ STATISTICS_FACE_DETECT_MODE_OFF);
+
+ if (fdMode != STATISTICS_FACE_DETECT_MODE_OFF && !mFaceDetectSupported) {
+ Log.w(TAG,
+ "processFaceDetectMode - Ignoring statistics.faceDetectMode; " +
+ "face detection is not available");
+ return;
+ }
+
+ // Print some warnings out in case the values were wrong
+ switch (fdMode) {
+ case STATISTICS_FACE_DETECT_MODE_OFF:
+ case STATISTICS_FACE_DETECT_MODE_SIMPLE:
+ break;
+ case STATISTICS_FACE_DETECT_MODE_FULL:
+ Log.w(TAG,
+ "processFaceDetectMode - statistics.faceDetectMode == FULL unsupported, " +
+ "downgrading to SIMPLE");
+ break;
+ default:
+ Log.w(TAG, "processFaceDetectMode - ignoring unknown statistics.faceDetectMode = "
+ + fdMode);
+ return;
+ }
+
+ boolean enableFaceDetect = fdMode != STATISTICS_FACE_DETECT_MODE_OFF;
+ synchronized (mLock) {
+ // Enable/disable face detection if it's changed since last time
+ if (enableFaceDetect != mFaceDetectEnabled) {
+ if (enableFaceDetect) {
+ mCamera.startFaceDetection();
+
+ if (VERBOSE) {
+ Log.v(TAG, "processFaceDetectMode - start face detection");
+ }
+ } else {
+ mCamera.stopFaceDetection();
+
+ if (VERBOSE) {
+ Log.v(TAG, "processFaceDetectMode - stop face detection");
+ }
+
+ mFaces = null;
+ }
+
+ mFaceDetectEnabled = enableFaceDetect;
+ }
+ }
+ }
+
+ /**
+ * Update the {@code result} camera metadata map with the new value for the
+ * {@code statistics.faces} and {@code statistics.faceDetectMode}.
+ *
+ * <p>Face detect callbacks are processed in the background, and each call to
+ * {@link #mapResultFaces} will have the latest faces as reflected by the camera1 callbacks.</p>
+ *
+ * @param result a non-{@code null} result
+ * @param legacyRequest a non-{@code null} request (read-only)
+ */
+ public void mapResultFaces(CameraMetadataNative result, LegacyRequest legacyRequest) {
+ checkNotNull(result, "result must not be null");
+ checkNotNull(legacyRequest, "legacyRequest must not be null");
+
+ Camera.Face[] faces, previousFaces;
+ int fdMode;
+ synchronized (mLock) {
+ fdMode = mFaceDetectEnabled ?
+ STATISTICS_FACE_DETECT_MODE_SIMPLE : STATISTICS_FACE_DETECT_MODE_OFF;
+
+ if (mFaceDetectEnabled) {
+ faces = mFaces;
+ } else {
+ faces = null;
+ }
+
+ previousFaces = mFacesPrev;
+ mFacesPrev = faces;
+ }
+
+ CameraCharacteristics characteristics = legacyRequest.characteristics;
+ CaptureRequest request = legacyRequest.captureRequest;
+ Size previewSize = legacyRequest.previewSize;
+ Camera.Parameters params = legacyRequest.parameters;
+
+ Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArray,
+ request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params);
+
+ List<Face> convertedFaces = new ArrayList<>();
+ if (faces != null) {
+ for (Camera.Face face : faces) {
+ if (face != null) {
+ convertedFaces.add(
+ ParameterUtils.convertFaceFromLegacy(face, activeArray, zoomData));
+ } else {
+ Log.w(TAG, "mapResultFaces - read NULL face from camera1 device");
+ }
+ }
+ }
+
+ if (VERBOSE && previousFaces != faces) { // Log only in verbose and IF the faces changed
+ Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces));
+ }
+
+ result.set(CaptureResult.STATISTICS_FACES, convertedFaces.toArray(new Face[0]));
+ result.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, fdMode);
+ }
+}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
index e576b43..d0a3a3f 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
@@ -247,7 +247,8 @@ public class LegacyFocusStateMapper {
// No action necessary. The callbacks will handle transitions.
break;
default:
- Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger);
+ Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = "
+ + afTrigger);
}
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 711edf4..b05508b 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -204,6 +204,11 @@ public class LegacyMetadataMapper {
mapSensor(m, p);
/*
+ * statistics.*
+ */
+ mapStatistics(m, p);
+
+ /*
* sync.*
*/
mapSync(m, p);
@@ -487,6 +492,18 @@ public class LegacyMetadataMapper {
private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
/*
+ * android.control.availableVideoStabilizationModes
+ */
+ {
+ int stabModes[] = p.isVideoStabilizationSupported() ?
+ new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ CONTROL_VIDEO_STABILIZATION_MODE_ON } :
+ new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF };
+
+ m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes);
+ }
+
+ /*
* android.control.maxRegions
*/
final int AE = 0, AWB = 1, AF = 2;
@@ -742,6 +759,31 @@ public class LegacyMetadataMapper {
m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize);
}
+ private static void mapStatistics(CameraMetadataNative m, Parameters p) {
+ /*
+ * statistics.info.availableFaceDetectModes
+ */
+ int[] fdModes;
+
+ if (p.getMaxNumDetectedFaces() > 0) {
+ fdModes = new int[] {
+ STATISTICS_FACE_DETECT_MODE_OFF,
+ STATISTICS_FACE_DETECT_MODE_SIMPLE
+ // FULL is never-listed, since we have no way to query it statically
+ };
+ } else {
+ fdModes = new int[] {
+ STATISTICS_FACE_DETECT_MODE_OFF
+ };
+ }
+ m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes);
+
+ /*
+ * statistics.info.maxFaceCount
+ */
+ m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces());
+ }
+
private static void mapSync(CameraMetadataNative m, Parameters p) {
/*
* sync.maxLatency
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index a6fe035..20f3fd2 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -150,10 +150,8 @@ public class LegacyRequestMapper {
if (supported) {
params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
- params.setRecordingHint(false);
} else {
Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
- params.setRecordingHint(true);
}
}
@@ -248,6 +246,18 @@ public class LegacyRequestMapper {
// TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
}
+ // control.videoStabilizationMode
+ {
+ Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
+ /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ params.isVideoStabilizationSupported(),
+ /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+
+ if (stabMode != null) {
+ params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ }
+ }
+
// lens.focusDistance
{
boolean infinityFocusSupported =
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 9eff943..a2487f4 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -35,6 +35,9 @@ import java.util.ArrayList;
import java.util.List;
import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON;
+import static android.hardware.camera2.CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE;
import static android.hardware.camera2.CaptureResult.*;
/**
@@ -142,7 +145,6 @@ public class LegacyResultMapper {
*/
mapAwb(result, /*out*/params);
-
/*
* control.mode
*/
@@ -171,7 +173,6 @@ public class LegacyResultMapper {
}
}
-
/*
* control.effectMode
*/
@@ -187,6 +188,15 @@ public class LegacyResultMapper {
}
}
+ // control.videoStabilizationMode
+ {
+ int stabMode =
+ (params.isVideoStabilizationSupported() && params.getVideoStabilization()) ?
+ CONTROL_VIDEO_STABILIZATION_MODE_ON :
+ CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+ result.set(CONTROL_VIDEO_STABILIZATION_MODE, stabMode);
+ }
+
/*
* flash
*/
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
index efd12f2..385f844 100644
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
@@ -43,6 +43,7 @@ import static com.android.internal.util.Preconditions.*;
/**
* Various utilities for dealing with camera API1 parameters.
*/
+@SuppressWarnings("deprecation")
public class ParameterUtils {
/** Upper/left minimal point of a normalized rectangle */
public static final int NORMALIZED_RECTANGLE_MIN = -1000;
@@ -164,19 +165,23 @@ public class ParameterUtils {
* <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX},
* the score is clipped first and a warning is printed to logcat.</p>
*
+ * <p>If the id is negative, the id is changed to 0 and a warning is printed to
+ * logcat.</p>
+ *
* <p>All other parameters are passed-through as-is.</p>
*
* @return a new face with the optional features set
*/
public Face toFace(
int id, Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+ int idSafe = clipLower(id, /*lo*/0, rect, "id");
int score = clip(weight,
Face.SCORE_MIN,
Face.SCORE_MAX,
rect,
"score");
- return new Face(rect, score, id, leftEyePosition, rightEyePosition, mouthPosition);
+ return new Face(rect, score, idSafe, leftEyePosition, rightEyePosition, mouthPosition);
}
/**
@@ -861,6 +866,61 @@ public class ParameterUtils {
/*usePreviewCrop*/true);
}
+ /**
+ * Convert an api1 face into an active-array based api2 face.
+ *
+ * <p>Out-of-ranges scores and ids will be clipped to be within range (with a warning).</p>
+ *
+ * @param face a non-{@code null} api1 face
+ * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
+ * @param zoomData the calculated zoom data corresponding to this request
+ *
+ * @return a non-{@code null} api2 face
+ *
+ * @throws NullPointerException if the {@code face} was {@code null}
+ */
+ public static Face convertFaceFromLegacy(Camera.Face face, Rect activeArray,
+ ZoomData zoomData) {
+ checkNotNull(face, "face must not be null");
+
+ Face api2Face;
+
+ Camera.Area fakeArea = new Camera.Area(face.rect, /*weight*/1);
+
+ WeightedRectangle faceRect =
+ convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, fakeArea);
+
+ Point leftEye = face.leftEye, rightEye = face.rightEye, mouth = face.mouth;
+ if (leftEye != null && rightEye != null && mouth != null) {
+ leftEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+ rightEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+ mouth = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+
+ api2Face = faceRect.toFace(face.id, leftEye, rightEye, mouth);
+ } else {
+ api2Face = faceRect.toFace();
+ }
+
+ return api2Face;
+ }
+
+ private static Point convertCameraPointToActiveArrayPoint(
+ Rect activeArray, ZoomData zoomData, Point point, boolean usePreviewCrop) {
+ Rect pointedRect = new Rect(point.x, point.y, point.x, point.y);
+ Camera.Area pointedArea = new Area(pointedRect, /*weight*/1);
+
+ WeightedRectangle adjustedRect =
+ convertCameraAreaToActiveArrayRectangle(activeArray,
+ zoomData, pointedArea, usePreviewCrop);
+
+ Point transformedPoint = new Point(adjustedRect.rect.left, adjustedRect.rect.top);
+
+ return transformedPoint;
+ }
+
private static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) {
Rect previewCrop = zoomData.previewCrop;
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index c556c32..ec233da7 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -39,7 +39,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import static com.android.internal.util.Preconditions.*;
@@ -55,18 +54,23 @@ import static com.android.internal.util.Preconditions.*;
* - An {@link CameraDeviceState} state machine that manages the callbacks for various operations.
* </p>
*/
+@SuppressWarnings("deprecation")
public class RequestThreadManager {
private final String TAG;
private final int mCameraId;
private final RequestHandlerThread mRequestThread;
private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
+ // For slightly more spammy messages that will get repeated every frame
+ private static final boolean VERBOSE =
+ Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.VERBOSE);
private final Camera mCamera;
private final CameraCharacteristics mCharacteristics;
private final CameraDeviceState mDeviceState;
private final CaptureCollector mCaptureCollector;
private final LegacyFocusStateMapper mFocusStateMapper;
+ private final LegacyFaceDetectMapper mFaceDetectMapper;
private static final int MSG_CONFIGURE_OUTPUTS = 1;
private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
@@ -219,6 +223,9 @@ public class RequestThreadManager {
};
private void stopPreview() {
+ if (VERBOSE) {
+ Log.v(TAG, "stopPreview - preview running? " + mPreviewRunning);
+ }
if (mPreviewRunning) {
mCamera.stopPreview();
mPreviewRunning = false;
@@ -226,14 +233,18 @@ public class RequestThreadManager {
}
private void startPreview() {
+ if (VERBOSE) {
+ Log.v(TAG, "startPreview - preview running? " + mPreviewRunning);
+ }
if (!mPreviewRunning) {
+ // XX: CameraClient:;startPreview is not getting called after a stop
mCamera.startPreview();
mPreviewRunning = true;
}
}
- private void doJpegCapture(RequestHolder request) throws IOException {
- if (DEBUG) Log.d(TAG, "doJpegCapture");
+ private void doJpegCapturePrepare(RequestHolder request) throws IOException {
+ if (DEBUG) Log.d(TAG, "doJpegCapturePrepare - preview running? " + mPreviewRunning);
if (!mPreviewRunning) {
if (DEBUG) Log.d(TAG, "doJpegCapture - create fake surface");
@@ -242,11 +253,20 @@ public class RequestThreadManager {
mCamera.setPreviewTexture(mDummyTexture);
startPreview();
}
+ }
+
+ private void doJpegCapture(RequestHolder request) {
+ if (DEBUG) Log.d(TAG, "doJpegCapturePrepare");
+
mCamera.takePicture(mJpegShutterCallback, /*raw*/null, mJpegCallback);
mPreviewRunning = false;
}
private void doPreviewCapture(RequestHolder request) throws IOException {
+ if (VERBOSE) {
+ Log.v(TAG, "doPreviewCapture - preview running? " + mPreviewRunning);
+ }
+
if (mPreviewRunning) {
return; // Already running
}
@@ -264,7 +284,20 @@ public class RequestThreadManager {
}
private void configureOutputs(Collection<Surface> outputs) throws IOException {
+ if (DEBUG) {
+ String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces");
+
+ Log.d(TAG, "configureOutputs with " + outputsStr);
+ }
+
stopPreview();
+ /*
+ * Try to release the previous preview's surface texture earlier if we end up
+ * using a different one; this also reduces the likelihood of getting into a deadlock
+ * when disconnecting from the old previous texture at a later time.
+ */
+ mCamera.setPreviewTexture(/*surfaceTexture*/null);
+
if (mGLThreadManager != null) {
mGLThreadManager.waitUntilStarted();
mGLThreadManager.ignoreNewFrames();
@@ -305,7 +338,6 @@ public class RequestThreadManager {
}
mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
- mParams.setRecordingHint(true);
if (mPreviewOutputs.size() > 0) {
List<Size> outputSizes = new ArrayList<>(outputs.size());
@@ -575,7 +607,6 @@ public class RequestThreadManager {
Log.e(TAG, "Interrupted while waiting for requests to complete.");
}
mDeviceState.setIdle();
- stopPreview();
break;
} else {
// Queue another capture if we did not get the last burst.
@@ -613,10 +644,6 @@ public class RequestThreadManager {
}
}
- // Unconditionally process AF triggers, since they're non-idempotent
- // - must be done after setting the most-up-to-date AF mode
- mFocusStateMapper.processRequestTriggers(request, mParams);
-
try {
boolean success = mCaptureCollector.queueRequest(holder,
mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -624,6 +651,8 @@ public class RequestThreadManager {
if (!success) {
Log.e(TAG, "Timed out while queueing capture request.");
}
+ // Starting the preview needs to happen before enabling
+ // face detection or auto focus
if (holder.hasPreviewTargets()) {
doPreviewCapture(holder);
}
@@ -635,12 +664,33 @@ public class RequestThreadManager {
Log.e(TAG, "Timed out waiting for prior requests to complete.");
}
mReceivedJpeg.close();
+ doJpegCapturePrepare(holder);
+ if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
+ // TODO: report error to CameraDevice
+ Log.e(TAG, "Hit timeout for jpeg callback!");
+ }
+ }
+
+ /*
+ * Do all the actions that require a preview to have been started
+ */
+
+ // Toggle face detection on/off
+ // - do this before AF to give AF a chance to use faces
+ mFaceDetectMapper.processFaceDetectMode(request, /*in*/mParams);
+
+ // Unconditionally process AF triggers, since they're non-idempotent
+ // - must be done after setting the most-up-to-date AF mode
+ mFocusStateMapper.processRequestTriggers(request, mParams);
+
+ if (holder.hasJpegTargets()) {
doJpegCapture(holder);
if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
// TODO: report error to CameraDevice
Log.e(TAG, "Hit timeout for jpeg callback!");
}
}
+
} catch (IOException e) {
// TODO: report error to CameraDevice
throw new IOError(e);
@@ -677,6 +727,8 @@ public class RequestThreadManager {
mLastRequest, timestampMutable.value);
// Update AF state
mFocusStateMapper.mapResultTriggers(result);
+ // Update detected faces list
+ mFaceDetectMapper.mapResultFaces(result, mLastRequest);
mDeviceState.setCaptureResult(holder, result);
}
@@ -731,6 +783,7 @@ public class RequestThreadManager {
TAG = name;
mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
mFocusStateMapper = new LegacyFocusStateMapper(mCamera);
+ mFaceDetectMapper = new LegacyFaceDetectMapper(mCamera, mCharacteristics);
mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 1efabb1..2e6b9ae 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -813,6 +813,7 @@ public final class StreamConfigurationMap {
switch (format) {
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
case HAL_PIXEL_FORMAT_BLOB:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
return format;
case ImageFormat.JPEG:
throw new IllegalArgumentException(
@@ -843,12 +844,6 @@ public final class StreamConfigurationMap {
* @throws IllegalArgumentException if the format was not user-defined
*/
static int checkArgumentFormat(int format) {
- // TODO: remove this hack , CTS shouldn't have been using internal constants
- if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
- Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway");
- return format;
- }
-
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
throw new IllegalArgumentException(String.format(
"format 0x%x was not defined in either ImageFormat or PixelFormat", format));
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index d4e6df5..51b7229 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -96,11 +96,9 @@ public final class DisplayManager {
* windows on the display and the system may mirror the contents of other displays
* onto it.
* </p><p>
- * Creating a public virtual display requires the
- * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
- * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
- * These permissions are reserved for use by system components and are not available to
- * third-party applications.
+ * Creating a public virtual display that isn't restricted to own-content only implicitly
+ * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for
+ * restrictions on who is allowed to create an auto-mirroring display.
* </p>
*
* <h3>Private virtual displays</h3>
@@ -108,6 +106,8 @@ public final class DisplayManager {
* When this flag is not set, the virtual display is private as defined by the
* {@link Display#FLAG_PRIVATE} display flag.
* </p>
+ *
+ * <p>
* A private virtual display belongs to the application that created it.
* Only the a owner of a private virtual display is allowed to place windows upon it.
* The private virtual display also does not participate in display mirroring: it will
@@ -115,10 +115,11 @@ public final class DisplayManager {
* be mirrored elsewhere. More precisely, the only processes that are allowed to
* enumerate or interact with the private display are those that have the same UID as the
* application that originally created the private virtual display.
- * </p>
+ * </p>
*
* @see #createVirtualDisplay
* @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ * @see #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
*/
public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
@@ -187,29 +188,51 @@ public final class DisplayManager {
* will be blanked instead if it has no windows.
* </p>
*
+ * <p>
+ * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. If both
+ * flags are specified then the own-content only behavior will be applied.
+ * </p>
+ *
+ * <p>
+ * This behavior of this flag is implied whenever neither {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}
+ * nor {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} have been set. This flag is only required to
+ * override the default behavior when creating a public display.
+ * </p>
+ *
* @see #createVirtualDisplay
*/
public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
/**
- * Virtual display flag: Indicates that the display is being created for
- * the purpose of screen sharing. This implies
- * VIRTUAL_DISPLAY_FLAG_PRIVATE. Other flags are not allowed (especially
- * not VIRTUAL_DISPLAY_FLAG_PUBLIC or PRESENTATION).
+ * Virtual display flag: Allows content to be mirrored on private displays when no content is
+ * being shown.
+ *
+ * <p>
+ * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
+ * If both flags are specified then the own-content only behavior will be applied.
+ * </p>
*
* <p>
- * Requires screen share permission for use.
+ * The behavior of this flag is implied whenever {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} is set
+ * and {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY} has not been set. This flag is only
+ * required to override the default behavior when creating a private display.
* </p>
*
* <p>
- * While a display of this type exists, the system will show some sort of
- * notification to the user indicating that the screen is being shared.
+ * Creating an auto-mirroing virtual display requires the
+ * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
+ * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+ * These permissions are reserved for use by system components and are not available to
+ * third-party applications.
+ *
+ * Alternatively, an appropriate {@link MediaProjection} may be used to create an
+ * auto-mirroring virtual display.
* </p>
*
* @see #createVirtualDisplay
*/
- public static final int VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE = 1 << 4;
+ public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
/** @hide */
public DisplayManager(Context context) {
@@ -489,7 +512,7 @@ public final class DisplayManager {
* @param flags A combination of virtual display flags:
* {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
- * or {@link #VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE}.
+ * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
* @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
diff --git a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
index f279668..2f6dbe7 100644
--- a/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
+++ b/core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl
@@ -34,4 +34,12 @@ oneway interface IRecognitionStatusCallback {
* @param status The error code that was seen.
*/
void onError(int status);
+ /**
+ * Called when the recognition is paused temporarily for some reason.
+ */
+ void onRecognitionPaused();
+ /**
+ * Called when the recognition is resumed after it was temporarily paused.
+ */
+ void onRecognitionResumed();
} \ No newline at end of file
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 786439e..3f18519 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.SystemApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
import android.content.Context;
@@ -127,6 +128,16 @@ public class TrafficStats {
}
/**
+ * System API for backup-related support components to tag network traffic
+ * appropriately.
+ * @hide
+ */
+ @SystemApi
+ public static void setThreadStatsTagBackup() {
+ setThreadStatsTag(TAG_SYSTEM_BACKUP);
+ }
+
+ /**
* Get the active tag used when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
* {@link #tagSocket(Socket)}.
@@ -160,11 +171,13 @@ public class TrafficStats {
*
* @hide
*/
+ @SystemApi
public static void setThreadStatsUid(int uid) {
NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
/** {@hide} */
+ @SystemApi
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 545b19a..7d086e1 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -33,6 +33,7 @@ import android.util.Printer;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import android.view.Display;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -158,7 +159,7 @@ public abstract class BatteryStats implements Parcelable {
private static final long BYTES_PER_MB = 1048576; // 1024^2
private static final long BYTES_PER_GB = 1073741824; //1024^3
-
+ private static final String VERSION_DATA = "vers";
private static final String UID_DATA = "uid";
private static final String APK_DATA = "apk";
private static final String PROCESS_DATA = "pr";
@@ -1462,6 +1463,21 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getStartClockTime();
/**
+ * Return platform version tag that we were running in when the battery stats started.
+ */
+ public abstract String getStartPlatformVersion();
+
+ /**
+ * Return platform version tag that we were running in when the battery stats ended.
+ */
+ public abstract String getEndPlatformVersion();
+
+ /**
+ * Return the internal version code of the parcelled format.
+ */
+ public abstract int getParcelVersion();
+
+ /**
* Return whether we are currently running on battery.
*/
public abstract boolean getIsOnBattery();
@@ -1596,6 +1612,27 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long computeBatteryTimeRemaining(long curTime);
+ // The part of a step duration that is the actual time.
+ public static final long STEP_LEVEL_TIME_MASK = 0x000000ffffffffffL;
+
+ // Bits in a step duration that are the new battery level we are at.
+ public static final long STEP_LEVEL_LEVEL_MASK = 0x0000ff0000000000L;
+ public static final long STEP_LEVEL_LEVEL_SHIFT = 40;
+
+ // Bits in a step duration that are the initial mode we were in at that step.
+ public static final long STEP_LEVEL_INITIAL_MODE_MASK = 0x00ff000000000000L;
+ public static final long STEP_LEVEL_INITIAL_MODE_SHIFT = 48;
+
+ // Bits in a step duration that indicate which modes changed during that step.
+ public static final long STEP_LEVEL_MODIFIED_MODE_MASK = 0xff00000000000000L;
+ public static final long STEP_LEVEL_MODIFIED_MODE_SHIFT = 56;
+
+ // Step duration mode: the screen is on, off, dozed, etc; value is Display.STATE_* - 1.
+ public static final int STEP_LEVEL_MODE_SCREEN_STATE = 0x03;
+
+ // Step duration mode: power save is on.
+ public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04;
+
/**
* Return the historical number of discharge steps we currently have.
*/
@@ -1986,7 +2023,8 @@ public abstract class BatteryStats implements Parcelable {
} else {
dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
- getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+ getDischargeAmountScreenOnSinceCharge(),
+ getDischargeAmountScreenOffSinceCharge());
}
if (reqUid < 0) {
@@ -3620,14 +3658,60 @@ public abstract class BatteryStats implements Parcelable {
if (!checkin) {
pw.println(header);
}
- String[] lineArgs = new String[1];
+ String[] lineArgs = new String[4];
for (int i=0; i<count; i++) {
+ long duration = steps[i] & STEP_LEVEL_TIME_MASK;
+ int level = (int)((steps[i] & STEP_LEVEL_LEVEL_MASK)
+ >> STEP_LEVEL_LEVEL_SHIFT);
+ long initMode = (steps[i] & STEP_LEVEL_INITIAL_MODE_MASK)
+ >> STEP_LEVEL_INITIAL_MODE_SHIFT;
+ long modMode = (steps[i] & STEP_LEVEL_MODIFIED_MODE_MASK)
+ >> STEP_LEVEL_MODIFIED_MODE_SHIFT;
if (checkin) {
- lineArgs[0] = Long.toString(steps[i]);
+ lineArgs[0] = Long.toString(duration);
+ lineArgs[1] = Integer.toString(level);
+ if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) {
+ switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+ case Display.STATE_OFF: lineArgs[2] = "s-"; break;
+ case Display.STATE_ON: lineArgs[2] = "s+"; break;
+ case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
+ case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
+ default: lineArgs[1] = "?"; break;
+ }
+ } else {
+ lineArgs[2] = "";
+ }
+ if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) {
+ lineArgs[3] = (initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0 ? "p+" : "p-";
+ } else {
+ lineArgs[3] = "";
+ }
dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
} else {
pw.print(" #"); pw.print(i); pw.print(": ");
- TimeUtils.formatDuration(steps[i], pw);
+ TimeUtils.formatDuration(duration, pw);
+ pw.print(" to "); pw.print(level);
+ boolean haveModes = false;
+ if ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) == 0) {
+ pw.print(" (");
+ switch ((int)(initMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
+ case Display.STATE_OFF: pw.print("screen-off"); break;
+ case Display.STATE_ON: pw.print("screen-on"); break;
+ case Display.STATE_DOZE: pw.print("screen-doze"); break;
+ case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
+ default: lineArgs[1] = "screen-?"; break;
+ }
+ haveModes = true;
+ }
+ if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) == 0) {
+ pw.print(haveModes ? ", " : " (");
+ pw.print((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0
+ ? "power-save-on" : "power-save-off");
+ haveModes = true;
+ }
+ if (haveModes) {
+ pw.print(")");
+ }
pw.println();
}
}
@@ -3808,6 +3892,9 @@ public abstract class BatteryStats implements Parcelable {
if (didPid) {
pw.println();
}
+ }
+
+ if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(),
getNumDischargeStepDurations(), false)) {
long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
@@ -3828,9 +3915,6 @@ public abstract class BatteryStats implements Parcelable {
}
pw.println();
}
- }
-
- if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
pw.println("Statistics since last charge:");
pw.println(" System starts: " + getStartCount()
+ ", currently on battery: " + getIsOnBattery());
@@ -3847,7 +3931,10 @@ public abstract class BatteryStats implements Parcelable {
public void dumpCheckinLocked(Context context, PrintWriter pw,
List<ApplicationInfo> apps, int flags, long histStart) {
prepareForDumpLocked();
-
+
+ dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA,
+ "10", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
+
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
final boolean filtering =
@@ -3908,7 +3995,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
}
- if (!filtering) {
+ if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
getNumDischargeStepDurations(), true);
String[] lineArgs = new String[1];
@@ -3926,8 +4013,6 @@ public abstract class BatteryStats implements Parcelable {
dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
(Object[])lineArgs);
}
- }
- if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1);
}
if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index c43644a..713fcd8 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -18,7 +18,6 @@
package android.os;
import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
import android.content.pm.UserInfo;
import android.content.RestrictionEntry;
import android.graphics.Bitmap;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index afbf983..5ce9d5c 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.SystemApi;
import android.util.SparseArray;
import java.io.PrintWriter;
@@ -237,6 +238,16 @@ public final class UserHandle implements Parcelable {
return getUserId(Process.myUid());
}
+ /**
+ * Returns true if this UserHandle refers to the owner user; false otherwise.
+ * @return true if this UserHandle refers to the owner user; false otherwise.
+ * @hide
+ */
+ @SystemApi
+ public final boolean isOwner() {
+ return this.equals(OWNER);
+ }
+
/** @hide */
public UserHandle(int h) {
mHandle = h;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 04e6227..3087506 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -864,15 +864,6 @@ public class UserManager {
}
/**
- * Kept during L development to simplify updating unbundled apps.
- * TODO: Remove after 2014-08-04
- * @hide
- */
- public String getBadgedLabelForUser(String label, UserHandle user) {
- return (String) getBadgedLabelForUser((CharSequence) label, user);
- }
-
- /**
* If the target user is a managed profile of the calling user or the caller
* is itself a managed profile, then this returns a drawable to use as a small
* icon to include in a view to distinguish it from the original icon.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index de1df56..733ab32 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2375,6 +2375,16 @@ public final class Settings {
public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
/**
+ * Whether automatic routing of system audio to USB audio peripheral is disabled.
+ * The value is boolean (1 or 0), where 1 means automatic routing is disabled,
+ * and 0 means automatic routing is enabled.
+ *
+ * @hide
+ */
+ public static final String USB_AUDIO_AUTOMATIC_ROUTING_DISABLED =
+ "usb_audio_automatic_routing_disabled";
+
+ /**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index b0ff947..4860b44 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -161,6 +161,8 @@ public class AlwaysOnHotwordDetector {
private static final int MSG_AVAILABILITY_CHANGED = 1;
private static final int MSG_HOTWORD_DETECTED = 2;
private static final int MSG_DETECTION_ERROR = 3;
+ private static final int MSG_DETECTION_PAUSE = 4;
+ private static final int MSG_DETECTION_RESUME = 5;
private final String mText;
private final String mLocale;
@@ -180,21 +182,27 @@ public class AlwaysOnHotwordDetector {
private int mAvailability = STATE_NOT_READY;
/**
- * Details of the audio that triggered the keyphrase.
+ * Additional payload for {@link Callback#onDetected}.
*/
- public static class TriggerAudio {
+ public static class EventPayload {
/**
- * Format of {@code data}.
+ * Indicates if {@code data} is the audio that triggered the keyphrase.
*/
- @NonNull
+ public final boolean isTriggerAudio;
+ /**
+ * Format of {@code data}. May be null if {@code isTriggerAudio} is false.
+ */
+ @Nullable
public final AudioFormat audioFormat;
/**
- * Raw audio data that triggered they keyphrase.
+ * Raw data associated with the event.
+ * This is the audio that triggered the keyphrase if {@code isTriggerAudio} is true.
*/
- @NonNull
+ @Nullable
public final byte[] data;
- private TriggerAudio(AudioFormat _audioFormat, byte[] _data) {
+ private EventPayload(boolean _isTriggerAudio, AudioFormat _audioFormat, byte[] _data) {
+ isTriggerAudio = _isTriggerAudio;
audioFormat = _audioFormat;
data = _data;
}
@@ -224,14 +232,27 @@ public class AlwaysOnHotwordDetector {
* Clients should start a recognition again once they are done handling this
* detection.
*
- * @param triggerAudio Optional trigger audio data, if it was requested during
+ * @param eventPayload Payload data for the detection event.
+ * This may contain the trigger audio, if requested when calling
* {@link AlwaysOnHotwordDetector#startRecognition(int)}.
*/
- void onDetected(@Nullable TriggerAudio triggerAudio);
+ void onDetected(@NonNull EventPayload eventPayload);
/**
* Called when the detection fails due to an error.
*/
void onError();
+ /**
+ * Called when the recognition is paused temporarily for some reason.
+ * This is an informational callback, and the clients shouldn't be doing anything here
+ * except showing an indication on their UI if they have to.
+ */
+ void onRecognitionPaused();
+ /**
+ * Called when the recognition is resumed after it was temporarily paused.
+ * This is an informational callback, and the clients shouldn't be doing anything here
+ * except showing an indication on their UI if they have to.
+ */
+ void onRecognitionResumed();
}
/**
@@ -487,22 +508,13 @@ public class AlwaysOnHotwordDetector {
@Override
public void onDetected(KeyphraseRecognitionEvent event) {
if (DBG) {
- Slog.d(TAG, "OnDetected(" + event + ")");
+ Slog.d(TAG, "onDetected(" + event + ")");
} else {
Slog.i(TAG, "onDetected");
}
- Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED);
- // FIXME: Check whether the event contains trigger data or not.
- // FIXME: Read the audio format from the event.
- if (event.data != null) {
- AudioFormat audioFormat = new AudioFormat.Builder()
- .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
- .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
- .setSampleRate(16000)
- .build();
- message.obj = new TriggerAudio(audioFormat, event.data);
- }
- message.sendToTarget();
+ Message.obtain(mHandler, MSG_HOTWORD_DETECTED,
+ new EventPayload(event.triggerInData, event.captureFormat, event.data))
+ .sendToTarget();
}
@Override
@@ -510,6 +522,18 @@ public class AlwaysOnHotwordDetector {
Slog.i(TAG, "onError: " + status);
mHandler.sendEmptyMessage(MSG_DETECTION_ERROR);
}
+
+ @Override
+ public void onRecognitionPaused() {
+ Slog.i(TAG, "onRecognitionPaused");
+ mHandler.sendEmptyMessage(MSG_DETECTION_PAUSE);
+ }
+
+ @Override
+ public void onRecognitionResumed() {
+ Slog.i(TAG, "onRecognitionResumed");
+ mHandler.sendEmptyMessage(MSG_DETECTION_RESUME);
+ }
}
class MyHandler extends Handler {
@@ -527,11 +551,17 @@ public class AlwaysOnHotwordDetector {
mExternalCallback.onAvailabilityChanged(msg.arg1);
break;
case MSG_HOTWORD_DETECTED:
- mExternalCallback.onDetected((TriggerAudio) msg.obj);
+ mExternalCallback.onDetected((EventPayload) msg.obj);
break;
case MSG_DETECTION_ERROR:
mExternalCallback.onError();
break;
+ case MSG_DETECTION_PAUSE:
+ mExternalCallback.onRecognitionPaused();
+ break;
+ case MSG_DETECTION_RESUME:
+ mExternalCallback.onRecognitionResumed();
+ break;
default:
super.handleMessage(msg);
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e3e328c..19d14bf 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -448,6 +448,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
void doDestroy() {
+ onDestroy();
if (mInitialized) {
mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
mInsetsComputer);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 910f862..a410aa9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -386,9 +386,6 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void scale(float sx, float sy) {
- // TODO: remove
- if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);
-
nScale(mRenderer, sx, sy);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index eee4973..099f153 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -598,9 +598,6 @@ public class RenderNode {
* @see #getScaleX()
*/
public boolean setScaleX(float scaleX) {
- if (scaleX > 1000000) {
- throw new IllegalArgumentException("Invalid scale: " + scaleX);
- }
return nSetScaleX(mNativeRenderNode, scaleX);
}
@@ -622,9 +619,6 @@ public class RenderNode {
* @see #getScaleY()
*/
public boolean setScaleY(float scaleY) {
- if (scaleY > 1000000) {
- throw new IllegalArgumentException("Invalid scale: " + scaleY);
- }
return nSetScaleY(mNativeRenderNode, scaleY);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 328d67c..8c2048d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4649,16 +4649,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* otherwise is returned.
*/
public boolean performClick() {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-
- ListenerInfo li = mListenerInfo;
+ final boolean result;
+ final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
- return true;
+ result = true;
+ } else {
+ result = false;
}
- return false;
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ return result;
}
/**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 1832cc3..571a8f0 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -266,7 +266,6 @@ public final class WindowInsets {
* {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
*
* @return true if the insets have been fully consumed.
- * @hide Pending API
*/
public boolean isConsumed() {
return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index d93ca2c..23894ee 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -175,7 +175,9 @@ public final class WebViewFactory {
String[] nativePaths = null;
try {
nativePaths = getWebViewNativeLibraryPaths();
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (Throwable t) {
+ // Log and discard errors at this stage as we must not crash the system server.
+ Log.e(LOGTAG, "error preparing webview native library", t);
}
prepareWebViewInSystemServer(nativePaths);
}
@@ -201,35 +203,37 @@ public final class WebViewFactory {
String[] nativeLibs = null;
try {
nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
- } catch (PackageManager.NameNotFoundException e) {
- }
-
- if (nativeLibs != null) {
- long newVmSize = 0L;
-
- for (String path : nativeLibs) {
- if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
- if (path == null) continue;
- File f = new File(path);
- if (f.exists()) {
- long length = f.length();
- if (length > newVmSize) {
- newVmSize = length;
+ if (nativeLibs != null) {
+ long newVmSize = 0L;
+
+ for (String path : nativeLibs) {
+ if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
+ if (path == null) continue;
+ File f = new File(path);
+ if (f.exists()) {
+ long length = f.length();
+ if (length > newVmSize) {
+ newVmSize = length;
+ }
}
}
- }
- if (DEBUG) {
- Log.v(LOGTAG, "Based on library size, need " + newVmSize +
- " bytes of address space.");
+ if (DEBUG) {
+ Log.v(LOGTAG, "Based on library size, need " + newVmSize +
+ " bytes of address space.");
+ }
+ // The required memory can be larger than the file on disk (due to .bss), and an
+ // upgraded version of the library will likely be larger, so always attempt to
+ // reserve twice as much as we think to allow for the library to grow during this
+ // boot cycle.
+ newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ Log.d(LOGTAG, "Setting new address space to " + newVmSize);
+ SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ Long.toString(newVmSize));
}
- // The required memory can be larger than the file on disk (due to .bss), and an
- // upgraded version of the library will likely be larger, so always attempt to reserve
- // twice as much as we think to allow for the library to grow during this boot cycle.
- newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
- Log.d(LOGTAG, "Setting new address space to " + newVmSize);
- SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
- Long.toString(newVmSize));
+ } catch (Throwable t) {
+ // Log and discard errors at this stage as we must not crash the system server.
+ Log.e(LOGTAG, "error preparing webview native library", t);
}
prepareWebViewInSystemServer(nativeLibs);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index aa0b94f..60ef693 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3857,13 +3857,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
firstChildTop == contentTop - mOverscrollDistance) ||
(mFirstPosition + childCount == mItemCount &&
lastChildBottom == contentBottom + mOverscrollDistance))) {
- if (mFlingRunnable == null) {
- mFlingRunnable = new FlingRunnable();
+ if (!dispatchNestedPreFling(0, -initialVelocity)) {
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+ mFlingRunnable.start(-initialVelocity);
+ dispatchNestedFling(0, -initialVelocity, true);
+ } else {
+ mTouchMode = TOUCH_MODE_REST;
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
}
- reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-
- mFlingRunnable.start(-initialVelocity);
- dispatchNestedFling(0, -initialVelocity, true);
} else {
mTouchMode = TOUCH_MODE_REST;
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
@@ -3992,6 +3996,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return super.onGenericMotionEvent(event);
}
+ /**
+ * Initiate a fling with the given velocity.
+ *
+ * <p>Applications can use this method to manually initiate a fling as if the user
+ * initiated it via touch interaction.</p>
+ *
+ * @param velocityY Vertical velocity in pixels per second
+ */
+ public void fling(int velocityY) {
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+ mFlingRunnable.start(-velocityY);
+ }
+
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return ((nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0);
@@ -4029,7 +4049,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mFlingRunnable == null) {
mFlingRunnable = new FlingRunnable();
}
- mFlingRunnable.start((int) velocityY);
+ if (!dispatchNestedPreFling(0, velocityY)) {
+ mFlingRunnable.start((int) velocityY);
+ }
return true;
}
return dispatchNestedFling(velocityX, velocityY, consumed);
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 74c66c8..d0a2eab 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -84,6 +84,9 @@ import libcore.icu.ICU;
public class DatePicker extends FrameLayout {
private static final String LOG_TAG = DatePicker.class.getSimpleName();
+ private static final int MODE_SPINNER = 1;
+ private static final int MODE_CALENDAR = 2;
+
private final DatePickerDelegate mDelegate;
/**
@@ -120,24 +123,28 @@ public class DatePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
- final boolean legacyMode = a.getBoolean(R.styleable.DatePicker_legacyMode, true);
+ int mode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
a.recycle();
- if (legacyMode) {
- mDelegate = createLegacyUIDelegate(context, attrs, defStyleAttr, defStyleRes);
- } else {
- mDelegate = createNewUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ switch (mode) {
+ case MODE_CALENDAR:
+ mDelegate = createCalendarUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ break;
+ case MODE_SPINNER:
+ default:
+ mDelegate = createSpinnerUIDelegate(context, attrs, defStyleAttr, defStyleRes);
+ break;
}
}
- private DatePickerDelegate createLegacyUIDelegate(Context context, AttributeSet attrs,
+ private DatePickerDelegate createSpinnerUIDelegate(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- return new LegacyDatePickerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
+ return new DatePickerSpinnerDelegate(this, context, attrs, defStyleAttr, defStyleRes);
}
- private DatePickerDelegate createNewUIDelegate(Context context, AttributeSet attrs,
+ private DatePickerDelegate createCalendarUIDelegate(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
- return new android.widget.DatePickerDelegate(this, context, attrs, defStyleAttr,
+ return new DatePickerCalendarDelegate(this, context, attrs, defStyleAttr,
defStyleRes);
}
@@ -454,7 +461,7 @@ public class DatePicker extends FrameLayout {
/**
* A delegate implementing the basic DatePicker
*/
- private static class LegacyDatePickerDelegate extends AbstractDatePickerDelegate {
+ private static class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
private static final String DATE_FORMAT = "MM/dd/yyyy";
@@ -500,7 +507,7 @@ public class DatePicker extends FrameLayout {
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
- LegacyDatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+ DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
diff --git a/core/java/android/widget/DatePickerDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index ddc565d..c0c76ac 100644
--- a/core/java/android/widget/DatePickerDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -52,7 +52,7 @@ import java.util.Locale;
/**
* A delegate for picking up a date (day / month / year).
*/
-class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implements
+class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements
View.OnClickListener, DatePickerController {
private static final int UNINITIALIZED = -1;
@@ -113,7 +113,7 @@ class DatePickerDelegate extends DatePicker.AbstractDatePickerDelegate implement
private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
- public DatePickerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+ public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 33cc66e..d263625 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -351,6 +351,7 @@ public class GridView extends AbsListView {
final int selectedPosition = mSelectedPosition;
View child = null;
+ final int nextChildDir = isLayoutRtl ? -1 : +1;
for (int pos = startPos; pos < last; pos++) {
// is this the selected item?
boolean selected = pos == selectedPosition;
@@ -359,9 +360,9 @@ public class GridView extends AbsListView {
final int where = flow ? -1 : pos - startPos;
child = makeAndAddView(pos, y, flow, nextLeft, selected, where);
- nextLeft += (isLayoutRtl ? -1 : +1) * columnWidth;
+ nextLeft += nextChildDir * columnWidth;
if (pos < last - 1) {
- nextLeft += horizontalSpacing;
+ nextLeft += nextChildDir * horizontalSpacing;
}
if (selected && (hasFocus || inClick)) {
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 546cc5f..f1aaa4d 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.Handler;
@@ -55,7 +56,7 @@ import java.util.Locale;
* <p>
* Functions like show() and hide() have no effect when MediaController
* is created in an xml layout.
- *
+ *
* MediaController will hide and
* show the buttons according to these rules:
* <ul>
@@ -70,32 +71,34 @@ import java.util.Locale;
*/
public class MediaController extends FrameLayout {
- private MediaPlayerControl mPlayer;
- private Context mContext;
- private View mAnchor;
- private View mRoot;
- private WindowManager mWindowManager;
- private Window mWindow;
- private View mDecor;
+ private MediaPlayerControl mPlayer;
+ private Context mContext;
+ private View mAnchor;
+ private View mRoot;
+ private WindowManager mWindowManager;
+ private Window mWindow;
+ private View mDecor;
private WindowManager.LayoutParams mDecorLayoutParams;
- private ProgressBar mProgress;
- private TextView mEndTime, mCurrentTime;
- private boolean mShowing;
- private boolean mDragging;
- private static final int sDefaultTimeout = 3000;
- private static final int FADE_OUT = 1;
- private static final int SHOW_PROGRESS = 2;
- private boolean mUseFastForward;
- private boolean mFromXml;
- private boolean mListenersSet;
+ private ProgressBar mProgress;
+ private TextView mEndTime, mCurrentTime;
+ private boolean mShowing;
+ private boolean mDragging;
+ private static final int sDefaultTimeout = 3000;
+ private static final int FADE_OUT = 1;
+ private static final int SHOW_PROGRESS = 2;
+ private boolean mUseFastForward;
+ private boolean mFromXml;
+ private boolean mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
- StringBuilder mFormatBuilder;
- Formatter mFormatter;
- private ImageButton mPauseButton;
- private ImageButton mFfwdButton;
- private ImageButton mRewButton;
- private ImageButton mNextButton;
- private ImageButton mPrevButton;
+ StringBuilder mFormatBuilder;
+ Formatter mFormatter;
+ private ImageButton mPauseButton;
+ private ImageButton mFfwdButton;
+ private ImageButton mRewButton;
+ private ImageButton mNextButton;
+ private ImageButton mPrevButton;
+ private CharSequence mPlayDescription;
+ private CharSequence mPauseDescription;
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -132,7 +135,7 @@ public class MediaController extends FrameLayout {
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
-
+
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
@@ -201,7 +204,7 @@ public class MediaController extends FrameLayout {
return false;
}
};
-
+
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
@@ -249,6 +252,11 @@ public class MediaController extends FrameLayout {
}
private void initControllerView(View v) {
+ Resources res = mContext.getResources();
+ mPlayDescription = res
+ .getText(com.android.internal.R.string.lockscreen_transport_play_description);
+ mPauseDescription = res
+ .getText(com.android.internal.R.string.lockscreen_transport_pause_description);
mPauseButton = (ImageButton) v.findViewById(com.android.internal.R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
@@ -271,7 +279,7 @@ public class MediaController extends FrameLayout {
}
}
- // By default these are hidden. They will be enabled when setPrevNextListeners() is called
+ // By default these are hidden. They will be enabled when setPrevNextListeners() is called
mNextButton = (ImageButton) v.findViewById(com.android.internal.R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
@@ -328,7 +336,7 @@ public class MediaController extends FrameLayout {
// the buttons.
}
}
-
+
/**
* Show the controller on screen. It will go away
* automatically after 'timeout' milliseconds of inactivity.
@@ -347,7 +355,7 @@ public class MediaController extends FrameLayout {
mShowing = true;
}
updatePausePlay();
-
+
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
@@ -359,7 +367,7 @@ public class MediaController extends FrameLayout {
mHandler.sendMessageDelayed(msg, timeout);
}
}
-
+
public boolean isShowing() {
return mShowing;
}
@@ -525,8 +533,10 @@ public class MediaController extends FrameLayout {
if (mPlayer.isPlaying()) {
mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_pause);
+ mPauseButton.setContentDescription(mPauseDescription);
} else {
mPauseButton.setImageResource(com.android.internal.R.drawable.ic_media_play);
+ mPauseButton.setContentDescription(mPlayDescription);
}
}
@@ -668,7 +678,7 @@ public class MediaController extends FrameLayout {
if (mRoot != null) {
installPrevNextListeners();
-
+
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index fd04890..dd312a6 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1577,9 +1577,11 @@ public class ScrollView extends FrameLayout {
private void flingWithNestedDispatch(int velocityY) {
final boolean canFling = (mScrollY > 0 || velocityY > 0) &&
(mScrollY < getScrollRange() || velocityY < 0);
- dispatchNestedFling(0, velocityY, canFling);
- if (canFling) {
- fling(velocityY);
+ if (!dispatchNestedPreFling(0, velocityY)) {
+ dispatchNestedFling(0, velocityY, canFling);
+ if (canFling) {
+ fling(velocityY);
+ }
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a0f7baf..b162e54 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.R;
+import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@@ -222,6 +223,8 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
* @attr ref android.R.styleable#TextView_imeActionId
* @attr ref android.R.styleable#TextView_editorExtras
* @attr ref android.R.styleable#TextView_elegantTextHeight
+ * @attr ref android.R.styleable#TextView_letterSpacing
+ * @attr ref android.R.styleable#TextView_fontFeatureSettings
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -2702,7 +2705,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @see #setLetterSpacing(float)
* @see Paint#setLetterSpacing
- * @hide
*/
public float getLetterSpacing() {
return mTextPaint.getLetterSpacing();
@@ -2716,7 +2718,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @see Paint#getLetterSpacing
*
* @attr ref android.R.styleable#TextView_letterSpacing
- * @hide
*/
@android.view.RemotableViewMethod
public void setLetterSpacing(float letterSpacing) {
@@ -2736,8 +2737,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @see #setFontFeatureSettings(String)
* @see Paint#setFontFeatureSettings
- * @hide
*/
+ @Nullable
public String getFontFeatureSettings() {
return mTextPaint.getFontFeatureSettings();
}
@@ -2747,14 +2748,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* font-feature-settings attribute:
* http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
*
+ * @param fontFeatureSettings font feature settings represented as CSS compatible string
* @see #getFontFeatureSettings()
* @see Paint#getFontFeatureSettings
*
* @attr ref android.R.styleable#TextView_fontFeatureSettings
- * @hide
*/
@android.view.RemotableViewMethod
- public void setFontFeatureSettings(String fontFeatureSettings) {
+ public void setFontFeatureSettings(@Nullable String fontFeatureSettings) {
if (fontFeatureSettings != mTextPaint.getFontFeatureSettings()) {
mTextPaint.setFontFeatureSettings(fontFeatureSettings);
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 026a8ee..c488666 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -45,6 +45,9 @@ import java.util.Locale;
*/
@Widget
public class TimePicker extends FrameLayout {
+ private static final int MODE_SPINNER = 1;
+ private static final int MODE_CLOCK = 2;
+
private final TimePickerDelegate mDelegate;
/**
@@ -77,15 +80,19 @@ public class TimePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
- final boolean legacyMode = a.getBoolean(R.styleable.TimePicker_legacyMode, true);
+ int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
- if (legacyMode) {
- mDelegate = new LegacyTimePickerDelegate(
- this, context, attrs, defStyleAttr, defStyleRes);
- } else {
- mDelegate = new android.widget.TimePickerDelegate(
- this, context, attrs, defStyleAttr, defStyleRes);
+ switch (mode) {
+ case MODE_CLOCK:
+ mDelegate = new TimePickerSpinnerDelegate(
+ this, context, attrs, defStyleAttr, defStyleRes);
+ break;
+ case MODE_SPINNER:
+ default:
+ mDelegate = new TimePickerClockDelegate(
+ this, context, attrs, defStyleAttr, defStyleRes);
+ break;
}
}
diff --git a/core/java/android/widget/LegacyTimePickerDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 70db211..8102c4a 100644
--- a/core/java/android/widget/LegacyTimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -18,6 +18,7 @@ package android.widget;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Parcel;
@@ -44,7 +45,7 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
/**
* A delegate implementing the basic TimePicker
*/
-class LegacyTimePickerDelegate extends TimePicker.AbstractTimePickerDelegate {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private static final boolean DEFAULT_ENABLED_STATE = true;
@@ -100,8 +101,8 @@ class LegacyTimePickerDelegate extends TimePicker.AbstractTimePickerDelegate {
}
};
- public LegacyTimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
super(delegator, context);
// process style attributes
@@ -171,7 +172,10 @@ class LegacyTimePickerDelegate extends TimePicker.AbstractTimePickerDelegate {
mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
/* Get the localized am/pm strings and use them in the spinner */
- mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
+ final Resources res = context.getResources();
+ final String amText = res.getString(R.string.time_picker_am_label);
+ final String pmText = res.getString(R.string.time_picker_pm_label);
+ mAmPmStrings = new String[] {amText, pmText};
// am/pm
View amPmView = mDelegator.findViewById(R.id.amPm);
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index c68619c..523965c 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -51,7 +51,7 @@ import java.util.Locale;
/**
* A view for selecting the time of day, in either 24 hour or AM/PM mode.
*/
-class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implements
+class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
RadialTimePickerView.OnValueSelectedListener {
private static final String TAG = "TimePickerDelegate";
@@ -119,8 +119,8 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
private Calendar mTempCalendar;
- public TimePickerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
super(delegator, context);
// process style attributes
@@ -134,6 +134,8 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
mSelectHours = res.getString(R.string.select_hours);
mMinutePickerDescription = res.getString(R.string.minute_picker_description);
mSelectMinutes = res.getString(R.string.select_minutes);
+ mAmText = res.getString(R.string.time_picker_am_label);
+ mPmText = res.getString(R.string.time_picker_pm_label);
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_holo);
@@ -182,10 +184,6 @@ class TimePickerDelegate extends TimePicker.AbstractTimePickerDelegate implement
R.id.radial_picker);
mDoneButton = (Button) mainView.findViewById(R.id.done_button);
- String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
- mAmText = amPmTexts[0];
- mPmText = amPmTexts[1];
-
setupListeners();
mAllowAutoAdvance = true;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 5655506..40965f0 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -18,6 +18,7 @@ package com.android.internal.app;
import com.android.internal.os.BatteryStatsImpl;
+import android.os.ParcelFileDescriptor;
import android.os.WorkSource;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
@@ -37,6 +38,8 @@ interface IBatteryStats {
// Remaining methods are only used in Java.
byte[] getStatistics();
+ ParcelFileDescriptor getStatisticsStream();
+
// Return the computed amount of time remaining on battery, in milliseconds.
// Returns -1 if nothing could be computed.
long computeBatteryTimeRemaining();
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 97e1102..d8dffe0 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -273,11 +273,15 @@ public class LocalTransport extends BackupTransport {
@Override
public int finishBackup() {
- if (DEBUG) Log.v(TAG, "finishBackup()");
+ if (DEBUG) Log.v(TAG, "finishBackup() of " + mFullTargetPackage);
+ return tearDownFullBackup();
+ }
+
+ // ------------------------------------------------------------------------------------
+ // Full backup handling
+
+ private int tearDownFullBackup() {
if (mSocket != null) {
- if (DEBUG) {
- Log.v(TAG, "Concluding full backup of " + mFullTargetPackage);
- }
try {
mFullBackupOutputStream.flush();
mFullBackupOutputStream.close();
@@ -286,7 +290,7 @@ public class LocalTransport extends BackupTransport {
mSocket.close();
} catch (IOException e) {
if (DEBUG) {
- Log.w(TAG, "Exception caught in finishBackup()", e);
+ Log.w(TAG, "Exception caught in tearDownFullBackup()", e);
}
return TRANSPORT_ERROR;
} finally {
@@ -296,8 +300,9 @@ public class LocalTransport extends BackupTransport {
return TRANSPORT_OK;
}
- // ------------------------------------------------------------------------------------
- // Full backup handling
+ private File tarballFile(String pkgName) {
+ return new File(mCurrentSetFullDir, pkgName);
+ }
@Override
public long requestFullBackupTime() {
@@ -329,7 +334,7 @@ public class LocalTransport extends BackupTransport {
mFullTargetPackage = targetPackage.packageName;
FileOutputStream tarstream;
try {
- File tarball = new File(mCurrentSetFullDir, mFullTargetPackage);
+ File tarball = tarballFile(mFullTargetPackage);
tarstream = new FileOutputStream(tarball);
} catch (FileNotFoundException e) {
return TRANSPORT_ERROR;
@@ -368,6 +373,19 @@ public class LocalTransport extends BackupTransport {
return TRANSPORT_OK;
}
+ // For now we can't roll back, so just tear everything down.
+ @Override
+ public void cancelFullBackup() {
+ if (DEBUG) {
+ Log.i(TAG, "Canceling full backup of " + mFullTargetPackage);
+ }
+ File archive = tarballFile(mFullTargetPackage);
+ tearDownFullBackup();
+ if (archive.exists()) {
+ archive.delete();
+ }
+ }
+
// ------------------------------------------------------------------------------------
// Restore handling
static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 };
diff --git a/core/java/com/android/internal/os/AtomicFile.java b/core/java/com/android/internal/os/AtomicFile.java
index 445d10a..5a83f33 100644
--- a/core/java/com/android/internal/os/AtomicFile.java
+++ b/core/java/com/android/internal/os/AtomicFile.java
@@ -40,7 +40,7 @@ import java.io.IOException;
* appropriate mutual exclusion invariants whenever it accesses the file.
* </p>
*/
-public class AtomicFile {
+public final class AtomicFile {
private final File mBaseName;
private final File mBackupName;
@@ -129,7 +129,16 @@ public class AtomicFile {
} catch (IOException e) {
}
}
-
+
+ public boolean exists() {
+ return mBaseName.exists() || mBackupName.exists();
+ }
+
+ public void delete() {
+ mBaseName.delete();
+ mBackupName.delete();
+ }
+
public FileInputStream openRead() throws FileNotFoundException {
if (mBackupName.exists()) {
mBaseName.delete();
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 6c9b4b8..63be2d4 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -30,19 +30,26 @@ import android.net.ConnectivityManager;
import android.os.BatteryStats;
import android.os.BatteryStats.Uid;
import android.os.Bundle;
+import android.os.MemoryFile;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.telephony.SignalStrength;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatterySipper.DrainType;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -55,7 +62,7 @@ import java.util.Map;
* The caller must initialize this class as soon as activity object is ready to use (for example, in
* onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
*/
-public class BatteryStatsHelper {
+public final class BatteryStatsHelper {
private static final boolean DEBUG = false;
@@ -63,6 +70,7 @@ public class BatteryStatsHelper {
private static BatteryStats sStatsXfer;
private static Intent sBatteryBroadcastXfer;
+ private static ArrayMap<File, BatteryStats> sFileXfer = new ArrayMap<>();
final private Context mContext;
final private boolean mCollectBatteryBroadcast;
@@ -117,6 +125,68 @@ public class BatteryStatsHelper {
mCollectBatteryBroadcast = collectBatteryBroadcast;
}
+ public void storeStatsHistoryInFile(String fname) {
+ synchronized (sFileXfer) {
+ File path = makeFilePath(mContext, fname);
+ sFileXfer.put(path, this.getStats());
+ FileOutputStream fout = null;
+ try {
+ fout = new FileOutputStream(path);
+ Parcel hist = Parcel.obtain();
+ getStats().writeToParcelWithoutUids(hist, 0);
+ byte[] histData = hist.marshall();
+ fout.write(histData);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to write history to file", e);
+ } finally {
+ if (fout != null) {
+ try {
+ fout.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+
+ public static BatteryStats statsFromFile(Context context, String fname) {
+ synchronized (sFileXfer) {
+ File path = makeFilePath(context, fname);
+ BatteryStats stats = sFileXfer.get(path);
+ if (stats != null) {
+ return stats;
+ }
+ FileInputStream fin = null;
+ try {
+ fin = new FileInputStream(path);
+ byte[] data = readFully(fin);
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ return com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to read history to file", e);
+ } finally {
+ if (fin != null) {
+ try {
+ fin.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ return getStats(IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME)));
+ }
+
+ public static void dropFile(Context context, String fname) {
+ makeFilePath(context, fname).delete();
+ }
+
+ private static File makeFilePath(Context context, String fname) {
+ return new File(context.getFilesDir(), fname);
+ }
+
/** Clears the current stats and forces recreating for future use. */
public void clearStats() {
mStats = null;
@@ -853,25 +923,64 @@ public class BatteryStatsHelper {
public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
+ public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+ return readFully(stream, stream.available());
+ }
+
+ public static byte[] readFully(FileInputStream stream, int avail) throws java.io.IOException {
+ int pos = 0;
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length-pos);
+ //Log.i("foo", "Read " + amt + " bytes at " + pos
+ // + " of avail " + data.length);
+ if (amt <= 0) {
+ //Log.i("foo", "**** FINISHED READING: pos=" + pos
+ // + " len=" + data.length);
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length-pos) {
+ byte[] newData = new byte[pos+avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
private void load() {
if (mBatteryInfo == null) {
return;
}
- try {
- byte[] data = mBatteryInfo.getStatistics();
- Parcel parcel = Parcel.obtain();
- parcel.unmarshall(data, 0, data.length);
- parcel.setDataPosition(0);
- BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
- .createFromParcel(parcel);
- stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
- mStats = stats;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException:", e);
- }
+ mStats = getStats(mBatteryInfo);
if (mCollectBatteryBroadcast) {
mBatteryBroadcast = mContext.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
}
+
+ private static BatteryStatsImpl getStats(IBatteryStats service) {
+ try {
+ ParcelFileDescriptor pfd = service.getStatisticsStream();
+ if (pfd != null) {
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ try {
+ byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
+ Parcel parcel = Parcel.obtain();
+ parcel.unmarshall(data, 0, data.length);
+ parcel.setDataPosition(0);
+ BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
+ .createFromParcel(parcel);
+ stats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
+ return stats;
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to read statistics stream", e);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException:", e);
+ }
+ return null;
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index aad1156..ee0d14b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -29,6 +29,7 @@ import android.net.wifi.WifiManager;
import android.os.BadParcelableException;
import android.os.BatteryManager;
import android.os.BatteryStats;
+import android.os.Build;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -91,7 +92,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 112 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 113 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -109,6 +110,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static int sNumSpeedSteps;
private final JournaledFile mFile;
+ public final AtomicFile mCheckinFile;
static final int MSG_UPDATE_WAKELOCKS = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
@@ -142,7 +144,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- private final MyHandler mHandler;
+ public final MyHandler mHandler;
private BatteryCallback mCallback;
@@ -199,8 +201,8 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mRecordingHistory = false;
int mNumHistoryItems;
- static final int MAX_HISTORY_BUFFER = 128*1024; // 128KB
- static final int MAX_MAX_HISTORY_BUFFER = 144*1024; // 144KB
+ static final int MAX_HISTORY_BUFFER = 256*1024; // 256KB
+ static final int MAX_MAX_HISTORY_BUFFER = 320*1024; // 320KB
final Parcel mHistoryBuffer = Parcel.obtain();
final HistoryItem mHistoryLastWritten = new HistoryItem();
final HistoryItem mHistoryLastLastWritten = new HistoryItem();
@@ -232,6 +234,8 @@ public final class BatteryStatsImpl extends BatteryStats {
int mStartCount;
long mStartClockTime;
+ String mStartPlatformVersion;
+ String mEndPlatformVersion;
long mUptime;
long mUptimeStart;
@@ -240,7 +244,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mWakeLockNesting;
boolean mWakeLockImportant;
- boolean mRecordAllWakeLocks;
+ boolean mRecordAllHistory;
boolean mNoAutoReset;
int mScreenState = Display.STATE_UNKNOWN;
@@ -340,7 +344,11 @@ public final class BatteryStatsImpl extends BatteryStats {
int mDischargeAmountScreenOff;
int mDischargeAmountScreenOffSinceCharge;
- static final int MAX_LEVEL_STEPS = 100;
+ static final int MAX_LEVEL_STEPS = 200;
+
+ int mInitStepMode = 0;
+ int mCurStepMode = 0;
+ int mModStepMode = 0;
int mLastDischargeStepLevel;
long mLastDischargeStepTime;
@@ -429,10 +437,11 @@ public final class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private String[] mWifiIfaces = new String[0];
- // For debugging
public BatteryStatsImpl() {
mFile = null;
+ mCheckinFile = null;
mHandler = null;
+ clearHistoryLocked();
}
public static interface TimeBaseObs {
@@ -2353,6 +2362,9 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_START, name, uid, 0)) {
return;
}
+ if (!mRecordAllHistory) {
+ return;
+ }
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
@@ -2371,9 +2383,12 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
- addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
getUidStatsLocked(uid).updateProcessStateLocked(name, Uid.PROCESS_STATE_NONE,
elapsedRealtime);
+ if (!mRecordAllHistory) {
+ return;
+ }
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
}
public void noteSyncStartLocked(String name, int uid) {
@@ -2427,11 +2442,41 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public void setRecordAllWakeLocksLocked(boolean enabled) {
- mRecordAllWakeLocks = enabled;
+ public void setRecordAllHistoryLocked(boolean enabled) {
+ mRecordAllHistory = enabled;
if (!enabled) {
// Clear out any existing state.
mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
+ // Record the currently running processes as stopping, now that we are no
+ // longer tracking them.
+ HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
+ HistoryItem.EVENT_PROC);
+ if (active != null) {
+ long mSecRealtime = SystemClock.elapsedRealtime();
+ final long mSecUptime = SystemClock.uptimeMillis();
+ for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+ SparseIntArray uids = ent.getValue();
+ for (int j=0; j<uids.size(); j++) {
+ addHistoryEventLocked(mSecRealtime, mSecUptime,
+ HistoryItem.EVENT_PROC_FINISH, ent.getKey(), uids.keyAt(j));
+ }
+ }
+ }
+ } else {
+ // Record the currently running processes as starting, now that we are tracking them.
+ HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
+ HistoryItem.EVENT_PROC);
+ if (active != null) {
+ long mSecRealtime = SystemClock.elapsedRealtime();
+ final long mSecUptime = SystemClock.uptimeMillis();
+ for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+ SparseIntArray uids = ent.getValue();
+ for (int j=0; j<uids.size(); j++) {
+ addHistoryEventLocked(mSecRealtime, mSecUptime,
+ HistoryItem.EVENT_PROC_START, ent.getKey(), uids.keyAt(j));
+ }
+ }
+ }
}
}
@@ -2452,7 +2497,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (historyName == null) {
historyName = name;
}
- if (mRecordAllWakeLocks) {
+ if (mRecordAllHistory) {
if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
uid, 0)) {
addHistoryEventLocked(elapsedRealtime, uptime,
@@ -2496,7 +2541,7 @@ public final class BatteryStatsImpl extends BatteryStats {
uid = mapUid(uid);
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
- if (mRecordAllWakeLocks) {
+ if (mRecordAllHistory) {
if (historyName == null) {
historyName = name;
}
@@ -2788,6 +2833,16 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
+ ", newState=" + Display.stateToString(state));
+ if (state != Display.STATE_UNKNOWN) {
+ int stepState = state-1;
+ if (stepState < 4) {
+ mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_SCREEN_STATE) ^ stepState;
+ mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_SCREEN_STATE) | stepState;
+ } else {
+ Slog.wtf(TAG, "Unexpected screen state: " + state);
+ }
+ }
+
if (state == Display.STATE_ON) {
// Screen turning on.
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -2924,6 +2979,9 @@ public final class BatteryStatsImpl extends BatteryStats {
public void noteLowPowerMode(boolean enabled) {
if (mLowPowerModeEnabled != enabled) {
+ int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
+ mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
+ mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mLowPowerModeEnabled = enabled;
@@ -3871,6 +3929,18 @@ public final class BatteryStatsImpl extends BatteryStats {
return mStartClockTime;
}
+ @Override public String getStartPlatformVersion() {
+ return mStartPlatformVersion;
+ }
+
+ @Override public String getEndPlatformVersion() {
+ return mEndPlatformVersion;
+ }
+
+ @Override public int getParcelVersion() {
+ return VERSION;
+ }
+
@Override public boolean getIsOnBattery() {
return mOnBattery;
}
@@ -4535,6 +4605,7 @@ public final class BatteryStatsImpl extends BatteryStats {
proc.detach();
mProcessStats.removeAt(ip);
} else {
+ proc.reset();
active = true;
}
}
@@ -4791,7 +4862,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mProcessStats.clear();
for (int k = 0; k < numProcs; k++) {
String processName = in.readString();
- Uid.Proc proc = new Proc();
+ Uid.Proc proc = new Proc(processName);
proc.readFromParcelLocked(in);
mProcessStats.put(processName, proc);
}
@@ -5040,6 +5111,11 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
/**
+ * The name of this process.
+ */
+ final String mName;
+
+ /**
* Remains true until removed from the stats.
*/
boolean mActive = true;
@@ -5133,7 +5209,8 @@ public final class BatteryStatsImpl extends BatteryStats {
ArrayList<ExcessivePower> mExcessivePower;
- Proc() {
+ Proc(String name) {
+ mName = name;
mOnBatteryTimeBase.add(this);
mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
}
@@ -5148,6 +5225,24 @@ public final class BatteryStatsImpl extends BatteryStats {
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
}
+ void reset() {
+ mUserTime = mSystemTime = mForegroundTime = 0;
+ mStarts = 0;
+ mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
+ mLoadedStarts = 0;
+ mLastUserTime = mLastSystemTime = mLastForegroundTime = 0;
+ mLastStarts = 0;
+ mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
+ mUnpluggedStarts = 0;
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ SamplingCounter c = mSpeedBins[i];
+ if (c != null) {
+ c.reset(false);
+ }
+ }
+ mExcessivePower = null;
+ }
+
void detach() {
mActive = false;
mOnBatteryTimeBase.remove(this);
@@ -5736,7 +5831,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public Proc getProcessStatsLocked(String name) {
Proc ps = mProcessStats.get(name);
if (ps == null) {
- ps = new Proc();
+ ps = new Proc(name);
mProcessStats.put(name, ps);
}
@@ -6032,8 +6127,14 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public BatteryStatsImpl(String filename, Handler handler) {
- mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
+ public BatteryStatsImpl(File systemDir, Handler handler) {
+ if (systemDir != null) {
+ mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
+ new File(systemDir, "batterystats.bin.tmp"));
+ } else {
+ mFile = null;
+ }
+ mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6084,6 +6185,7 @@ public final class BatteryStatsImpl extends BatteryStats {
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
initTimes(uptime, realtime);
+ mStartPlatformVersion = mEndPlatformVersion = Build.ID;
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
mDischargePlugLevel = -1;
@@ -6095,6 +6197,7 @@ public final class BatteryStatsImpl extends BatteryStats {
public BatteryStatsImpl(Parcel p) {
mFile = null;
+ mCheckinFile = null;
mHandler = null;
clearHistoryLocked();
readFromParcel(p);
@@ -6390,6 +6493,10 @@ public final class BatteryStatsImpl extends BatteryStats {
private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+ if (!mRecordAllHistory && i == HistoryItem.EVENT_PROC) {
+ // Not recording process starts/stops.
+ continue;
+ }
HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
if (active == null) {
continue;
@@ -6455,7 +6562,37 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean reset = false;
if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
|| level >= 90
- || (mDischargeCurrentLevel < 20 && level >= 80))) {
+ || getLowDischargeAmountSinceCharge() >= 60)
+ || (getHighDischargeAmountSinceCharge() >= 60
+ && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER)) {
+ // Before we write, collect a snapshot of the final aggregated
+ // stats to be reported in the next checkin. Only do this if we have
+ // a sufficient amount of data to make it interesting.
+ if (getLowDischargeAmountSinceCharge() >= 20) {
+ final Parcel parcel = Parcel.obtain();
+ writeSummaryToParcel(parcel, true);
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override public void run() {
+ synchronized (mCheckinFile) {
+ FileOutputStream stream = null;
+ try {
+ stream = mCheckinFile.startWrite();
+ stream.write(parcel.marshall());
+ stream.flush();
+ FileUtils.sync(stream);
+ stream.close();
+ mCheckinFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w("BatteryStats",
+ "Error writing checkin battery statistics", e);
+ mCheckinFile.failWrite(stream);
+ } finally {
+ parcel.recycle();
+ }
+ }
+ }
+ });
+ }
doWrite = true;
resetAllStatsLocked();
mDischargeStartLevel = level;
@@ -6465,6 +6602,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mLastDischargeStepTime = -1;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
@@ -6504,6 +6643,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = -1;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
@@ -6529,14 +6670,17 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int BATTERY_PLUGGED_NONE = 0;
private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
- int numStepLevels, long elapsedRealtime) {
+ int numStepLevels, long modeBits, long elapsedRealtime) {
if (lastStepTime >= 0 && numStepLevels > 0) {
long duration = elapsedRealtime - lastStepTime;
for (int i=0; i<numStepLevels; i++) {
System.arraycopy(steps, 0, steps, 1, steps.length-1);
long thisDuration = duration / (numStepLevels-i);
duration -= thisDuration;
- steps[0] = thisDuration;
+ if (thisDuration > STEP_LEVEL_TIME_MASK) {
+ thisDuration = STEP_LEVEL_TIME_MASK;
+ }
+ steps[0] = thisDuration | modeBits;
}
stepCount += numStepLevels;
if (stepCount > steps.length) {
@@ -6623,23 +6767,30 @@ public final class BatteryStatsImpl extends BatteryStats {
if (changed) {
addHistoryRecordLocked(elapsedRealtime, uptime);
}
+ long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
+ | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
+ | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
if (onBattery) {
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
mNumDischargeStepDurations, mLastDischargeStepTime,
- mLastDischargeStepLevel - level, elapsedRealtime);
+ mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mLastDischargeStepTime = elapsedRealtime;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
}
} else {
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
mNumChargeStepDurations, mLastChargeStepTime,
- level - mLastChargeStepLevel, elapsedRealtime);
+ level - mLastChargeStepLevel, modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = elapsedRealtime;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
}
}
}
@@ -6863,7 +7014,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
long total = 0;
for (int i=0; i<numSteps; i++) {
- total += steps[i];
+ total += steps[i] & STEP_LEVEL_TIME_MASK;
}
return total / numSteps;
/*
@@ -6875,7 +7026,7 @@ public final class BatteryStatsImpl extends BatteryStats {
long totalTime = 0;
int num = 0;
for (int j=0; j<numToAverage && (i+j)<numSteps; j++) {
- totalTime += steps[i+j];
+ totalTime += steps[i+j] & STEP_LEVEL_TIME_MASK;
num++;
}
buckets[numBuckets] = totalTime / num;
@@ -7213,7 +7364,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
Parcel out = Parcel.obtain();
- writeSummaryToParcel(out);
+ writeSummaryToParcel(out, true);
mLastWriteTime = SystemClock.elapsedRealtime();
if (mPendingWrite != null) {
@@ -7224,14 +7375,11 @@ public final class BatteryStatsImpl extends BatteryStats {
if (sync) {
commitPendingDataToDisk();
} else {
- Thread thr = new Thread("BatteryStats-Write") {
- @Override
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override public void run() {
commitPendingDataToDisk();
}
- };
- thr.start();
+ });
}
}
@@ -7263,29 +7411,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- static byte[] readFully(FileInputStream stream) throws java.io.IOException {
- int pos = 0;
- int avail = stream.available();
- byte[] data = new byte[avail];
- while (true) {
- int amt = stream.read(data, pos, data.length-pos);
- //Log.i("foo", "Read " + amt + " bytes at " + pos
- // + " of avail " + data.length);
- if (amt <= 0) {
- //Log.i("foo", "**** FINISHED READING: pos=" + pos
- // + " len=" + data.length);
- return data;
- }
- pos += amt;
- avail = stream.available();
- if (avail > data.length-pos) {
- byte[] newData = new byte[pos+avail];
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
public void readLocked() {
if (mFile == null) {
Slog.w("BatteryStats", "readLocked: no file associated with this instance");
@@ -7301,7 +7426,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
FileInputStream stream = new FileInputStream(file);
- byte[] raw = readFully(stream);
+ byte[] raw = BatteryStatsHelper.readFully(stream);
Parcel in = Parcel.obtain();
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
@@ -7312,6 +7437,8 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.e("BatteryStats", "Error reading battery statistics", e);
}
+ mEndPlatformVersion = Build.ID;
+
if (mHistoryBuffer.dataPosition() > 0) {
mRecordingHistory = true;
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -7410,7 +7537,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- void writeHistory(Parcel out, boolean andOldHistory) {
+ void writeHistory(Parcel out, boolean inclData, boolean andOldHistory) {
if (DEBUG_HISTORY) {
StringBuilder sb = new StringBuilder(128);
sb.append("****************** WRITING mHistoryBaseTime: ");
@@ -7420,6 +7547,11 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.i(TAG, sb.toString());
}
out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
+ if (!inclData) {
+ out.writeInt(0);
+ out.writeInt(0);
+ return;
+ }
out.writeInt(mHistoryTagPool.size());
for (HashMap.Entry<HistoryTag, Integer> ent : mHistoryTagPool.entrySet()) {
HistoryTag tag = ent.getKey();
@@ -7449,7 +7581,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(-1);
}
- private void readSummaryFromParcel(Parcel in) {
+ public void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
Slog.w("BatteryStats", "readFromParcel: version got " + version
@@ -7463,6 +7595,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mUptime = in.readLong();
mRealtime = in.readLong();
mStartClockTime = in.readLong();
+ mStartPlatformVersion = in.readString();
+ mEndPlatformVersion = in.readString();
mOnBatteryTimeBase.readSummaryFromParcel(in);
mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
mDischargeUnplugLevel = in.readInt();
@@ -7742,7 +7876,7 @@ public final class BatteryStatsImpl extends BatteryStats {
*
* @param out the Parcel to be written to.
*/
- public void writeSummaryToParcel(Parcel out) {
+ public void writeSummaryToParcel(Parcel out, boolean inclHistory) {
pullPendingStateUpdatesLocked();
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
@@ -7750,12 +7884,14 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(VERSION);
- writeHistory(out, true);
+ writeHistory(out, inclHistory, true);
out.writeInt(mStartCount);
out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
out.writeLong(mStartClockTime);
+ out.writeString(mStartPlatformVersion);
+ out.writeString(mEndPlatformVersion);
mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
out.writeInt(mDischargeUnplugLevel);
@@ -8043,6 +8179,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mStartCount = in.readInt();
mStartClockTime = in.readLong();
+ mStartPlatformVersion = in.readString();
+ mEndPlatformVersion = in.readString();
mUptime = in.readLong();
mUptimeStart = in.readLong();
mRealtime = in.readLong();
@@ -8194,10 +8332,12 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(MAGIC);
- writeHistory(out, false);
+ writeHistory(out, true, false);
out.writeInt(mStartCount);
out.writeLong(mStartClockTime);
+ out.writeString(mStartPlatformVersion);
+ out.writeString(mEndPlatformVersion);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mRealtime);
diff --git a/core/java/com/android/internal/util/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
index eeffc16..9f775d3 100644
--- a/core/java/com/android/internal/util/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -20,7 +20,7 @@ import java.io.File;
import java.io.IOException;
/**
- * @Deprecated Use {@link com.android.internal.os.AtomicFile} instead. It would
+ * @deprecated Use {@link com.android.internal.os.AtomicFile} instead. It would
* be nice to update all existing uses of this to switch to AtomicFile, but since
* their on-file semantics are slightly different that would run the risk of losing
* data if at the point of the platform upgrade to the new code it would need to