Merge "Rename API to match StorageStats." into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index f32f23dd..161fef4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41027,7 +41027,6 @@
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
- method public java.lang.String[] getNamesForUids(int[]);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -49062,6 +49061,7 @@
method public int getProgress();
method public boolean getRendererPriorityWaivedWhenNotVisible();
method public int getRendererRequestedPriority();
+ method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
method public android.view.textclassifier.TextClassifier getTextClassifier();
diff --git a/api/system-current.txt b/api/system-current.txt
index 97e1f4a..92bc7b0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -263,6 +263,7 @@
field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
+ field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -11365,6 +11366,8 @@
method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean hasSystemFeature(java.lang.String, int);
+ method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract boolean isInstantApp();
method public abstract boolean isInstantApp(java.lang.String);
method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
@@ -44699,7 +44702,6 @@
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
- method public java.lang.String[] getNamesForUids(int[]);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -44730,6 +44732,8 @@
method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean hasSystemFeature(java.lang.String);
method public boolean hasSystemFeature(java.lang.String, int);
+ method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean isInstantApp();
method public boolean isInstantApp(java.lang.String);
method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
@@ -52844,6 +52848,7 @@
method public int getProgress();
method public boolean getRendererPriorityWaivedWhenNotVisible();
method public int getRendererRequestedPriority();
+ method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
method public android.view.textclassifier.TextClassifier getTextClassifier();
@@ -52908,7 +52913,6 @@
method public void zoomBy(float);
method public boolean zoomIn();
method public boolean zoomOut();
- field public static final java.lang.String DATA_REDUCTION_PROXY_SETTING_CHANGED = "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
@@ -53096,6 +53100,7 @@
method public abstract java.lang.String findAddress(java.lang.String);
method public abstract void freeMemoryForTests();
method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
+ method public abstract android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
method public abstract void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
diff --git a/api/test-current.txt b/api/test-current.txt
index ccdca6a..31f09c4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41281,7 +41281,6 @@
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
- method public java.lang.String[] getNamesForUids(int[]);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -49509,6 +49508,7 @@
method public int getProgress();
method public boolean getRendererPriorityWaivedWhenNotVisible();
method public int getRendererRequestedPriority();
+ method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
method public deprecated float getScale();
method public android.webkit.WebSettings getSettings();
method public android.view.textclassifier.TextClassifier getTextClassifier();
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 42e6147..7aa80d2 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -103,6 +103,18 @@
* {@link android.app.backup.BackupAgentHelper}. That class is particularly
* suited to handling of simple file or {@link android.content.SharedPreferences}
* backup and restore.
+ * <p>
+ * <b>Threading</b>
+ * <p>
+ * The constructor, as well as {@link #onCreate()} and {@link #onDestroy()} lifecycle callbacks run
+ * on the main thread (UI thread) of the application that implements the BackupAgent.
+ * The data-handling callbacks:
+ * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()},
+ * {@link #onFullBackup(FullBackupDataOutput)},
+ * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()},
+ * {@link #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long) onRestoreFile()},
+ * {@link #onRestoreFinished()}, and {@link #onQuotaExceeded(long, long) onQuotaExceeded()}
+ * run on binder pool threads.
*
* @see android.app.backup.BackupManager
* @see android.app.backup.BackupAgentHelper
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index adc6467..449b4a9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -47,6 +47,7 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -2314,7 +2315,9 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
- * {@link #hasSystemFeature}: The device supports Wi-Fi Passpoint.
+ * {@link #hasSystemFeature}: The device supports Wi-Fi Passpoint and all
+ * Passpoint related APIs in {@link WifiManager} are supported. Refer to
+ * {@link WifiManager#addOrUpdatePasspointConfiguration} for more info.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
@@ -4718,6 +4721,7 @@
* on the system for other users, also install it for the calling user.
* @hide
*/
+ @SystemApi
public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
/**
@@ -4725,6 +4729,7 @@
* on the system for other users, also install it for the calling user.
* @hide
*/
+ @SystemApi
public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
throws NameNotFoundException;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index e48bce1..135d92b 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -76,6 +76,7 @@
void onBusy();
void onCaptureStarted(RequestHolder holder, long timestamp);
void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
+ void onRequestQueueEmpty();
void onRepeatingRequestError(long lastFrameNumber);
}
@@ -218,6 +219,20 @@
}
/**
+ * Indicate that request queue (non-repeating) becomes empty.
+ *
+ * <p> Send notification that all non-repeating requests have been sent to camera device. </p>
+ */
+ public synchronized void setRequestQueueEmpty() {
+ mCurrentHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCurrentListener.onRequestQueueEmpty();
+ }
+ });
+ }
+
+ /**
* Set the listener for state transition callbacks.
*
* @param handler handler on which to call the callbacks.
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index f87d8c1..d8df9a0 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -504,12 +504,18 @@
if (mLegacyDevice.isClosed()) {
String err = "Cannot end configure, device has been closed.";
Log.e(TAG, err);
+ synchronized(mConfigureLock) {
+ mConfiguring = false;
+ }
throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
}
if (operatingMode != ICameraDeviceUser.NORMAL_MODE) {
String err = "LEGACY devices do not support this operating mode";
Log.e(TAG, err);
+ synchronized(mConfigureLock) {
+ mConfiguring = false;
+ }
throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 1a05904..621ea84 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -223,6 +223,25 @@
}
@Override
+ public void onRequestQueueEmpty() {
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) {
+ Log.d(TAG, "doing onRequestQueueEmpty callback");
+ }
+ try {
+ mDeviceCallbacks.onRequestQueueEmpty();
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onRequestQueueEmpty callback: ",
+ e);
+ }
+ }
+ });
+ }
+
+ @Override
public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index 8f252a1..407e5e6 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -18,7 +18,6 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.SubmitInfo;
import android.util.Log;
-import android.util.Pair;
import java.util.ArrayDeque;
import java.util.List;
@@ -41,6 +40,28 @@
private int mCurrentRequestId = 0;
private final List<Long> mJpegSurfaceIds;
+ public final class RequestQueueEntry {
+ private final BurstHolder mBurstHolder;
+ private final Long mFrameNumber;
+ private final boolean mQueueEmpty;
+
+ public BurstHolder getBurstHolder() {
+ return mBurstHolder;
+ }
+ public Long getFrameNumber() {
+ return mFrameNumber;
+ }
+ public boolean isQueueEmpty() {
+ return mQueueEmpty;
+ }
+
+ public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) {
+ mBurstHolder = burstHolder;
+ mFrameNumber = frameNumber;
+ mQueueEmpty = queueEmpty;
+ }
+ }
+
public RequestQueue(List<Long> jpegSurfaceIds) {
mJpegSurfaceIds = jpegSurfaceIds;
}
@@ -50,10 +71,12 @@
*
* <p>If a repeating burst is returned, it will not be removed.</p>
*
- * @return a pair containing the next burst and the current frame number, or null if none exist.
+ * @return an entry containing the next burst, the current frame number, and flag about whether
+ * request queue becomes empty. Null if no burst exists.
*/
- public synchronized Pair<BurstHolder, Long> getNext() {
+ public synchronized RequestQueueEntry getNext() {
BurstHolder next = mRequestQueue.poll();
+ boolean queueEmptied = (next != null && mRequestQueue.size() == 0);
if (next == null && mRepeatingRequest != null) {
next = mRepeatingRequest;
mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
@@ -64,7 +87,7 @@
return null;
}
- Pair<BurstHolder, Long> ret = new Pair<BurstHolder, Long>(next, mCurrentFrameNumber);
+ RequestQueueEntry ret = new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied);
mCurrentFrameNumber += next.getNumberOfRequests();
return ret;
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index da62f54..565a43e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -504,6 +504,15 @@
previews.add(new Pair<>(p, previewSizeIter.next()));
}
mGLThreadManager.setConfigurationAndWait(previews, mCaptureCollector);
+
+ for (Surface p : mPreviewOutputs) {
+ try {
+ LegacyCameraDevice.setSurfaceOrientation(p, facing, orientation);
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.e(TAG, "Surface abandoned, skipping setSurfaceOrientation()", e);
+ }
+ }
+
mGLThreadManager.allowNewFrames();
mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
if (mPreviewTexture != null) {
@@ -713,7 +722,7 @@
boolean anyRequestOutputAbandoned = false;
// Get the next burst from the request queue.
- Pair<BurstHolder, Long> nextBurst = mRequestQueue.getNext();
+ RequestQueue.RequestQueueEntry nextBurst = mRequestQueue.getNext();
if (nextBurst == null) {
// If there are no further requests queued, wait for any currently executing
@@ -748,11 +757,17 @@
if (nextBurst != null) {
// Queue another capture if we did not get the last burst.
handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
+
+ // Check whether capture queue becomes empty
+ if (nextBurst.isQueueEmpty()) {
+ mDeviceState.setRequestQueueEmpty();
+ }
}
// Complete each request in the burst
+ BurstHolder burstHolder = nextBurst.getBurstHolder();
List<RequestHolder> requests =
- nextBurst.first.produceRequestHolders(nextBurst.second);
+ burstHolder.produceRequestHolders(nextBurst.getFrameNumber());
for (RequestHolder holder : requests) {
CaptureRequest request = holder.getRequest();
@@ -918,8 +933,8 @@
}
// Stop the repeating request if any of its output surfaces is abandoned.
- if (anyRequestOutputAbandoned && nextBurst.first.isRepeating()) {
- long lastFrameNumber = cancelRepeating(nextBurst.first.getRequestId());
+ if (anyRequestOutputAbandoned && burstHolder.isRepeating()) {
+ long lastFrameNumber = cancelRepeating(burstHolder.getRequestId());
if (DEBUG) {
Log.d(TAG, "Stopped repeating request. Last frame number is " +
lastFrameNumber);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index 722b659..73733a0 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -76,7 +76,7 @@
/**
* Returns an {@link AccessibilityNodeInfo} representing a virtual view,
- * i.e. a descendant of the host View, with the given <code>virtualViewId</code>
+ * such as a descendant of the host View, with the given <code>virtualViewId</code>
* or the host View itself if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
* <p>
* A virtual descendant is an imaginary View that is reported as a part of the view
@@ -123,7 +123,7 @@
}
/**
- * Performs an accessibility action on a virtual view, i.e. a descendant of the
+ * Performs an accessibility action on a virtual view, such as a descendant of the
* host View, with the given <code>virtualViewId</code> or the host View itself
* if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
*
@@ -160,7 +160,7 @@
}
/**
- * Find the virtual view, i.e. a descendant of the host View, that has the
+ * Find the virtual view, such as a descendant of the host View, that has the
* specified focus type.
*
* @param focus The focus to find. One of
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 2ccd2ba..0d0f1cc 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -21,6 +21,11 @@
* created by the WebView and passed to {@link android.webkit.WebViewClient#onSafeBrowsingHit}. The
* host application must call {@link #showInterstitial(boolean)}, {@link #proceed(boolean)}, or
* {@link #backToSafety(boolean)} to set the WebView's response to the Safe Browsing hit.
+ *
+ * <p>
+ * If reporting is enabled, all reports will be sent according to the privacy policy referenced by
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
+ * </p>
*/
public abstract class SafeBrowsingResponse {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index dd716eb..650c7d9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -347,16 +347,6 @@
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
- /**
- * Broadcast Action: Indicates the data reduction proxy setting changed.
- * Sent by the settings app when user changes the data reduction proxy value. This intent will
- * always stay as a hidden API.
- * @hide
- */
- @SystemApi
- public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
- "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
-
private static final String LOGTAG = "WebView";
// Throwing an exception for incorrect thread usage if the
@@ -1700,6 +1690,16 @@
}
/**
+ * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+ *
+ * @return the url pointing to a privacy policy document which can be displayed to users.
+ */
+ @NonNull
+ public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+ return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+ }
+
+ /**
* Gets the WebBackForwardList for this WebView. This contains the
* back/forward list for use in querying each item in the history stack.
* This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 613eb72..4f6513f 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
@@ -95,6 +96,13 @@
* ValueCallback<Boolean>)}
*/
void setSafeBrowsingWhitelist(List<String> urls, ValueCallback<Boolean> callback);
+
+ /**
+ * Implement the API method
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}
+ */
+ @NonNull
+ Uri getSafeBrowsingPrivacyPolicyUrl();
}
Statics getStatics();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b55ad21..5b0f8d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2261,7 +2261,7 @@
<p>An application requesting this permission is responsible for
verifying the source and integrity of the update before passing
it off to the installer components.
- @hide -->
+ @SystemApi @hide -->
<permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
android:protectionLevel="signature|privileged" />
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index 29b6fd0..c707240 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -131,7 +131,9 @@
// find FM band and build its config
mModule = mModules.get(0);
+
for (RadioManager.BandDescriptor band : mModule.getBands()) {
+ Log.d(TAG, "Band: " + band);
int bandType = band.getType();
if (bandType == RadioManager.BAND_AM || bandType == RadioManager.BAND_AM_HD) {
mAmBandDescriptor = (RadioManager.AmBandDescriptor)band;
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index dbbbfc6..26e65dd 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -57,10 +57,10 @@
* SoundPool will automatically stop a previously playing stream based first
* on priority and then by age within that priority. Limiting the maximum
* number of streams helps to cap CPU loading and reducing the likelihood that
- * audio mixing will impact visuals or UI performance.</p>
+ * audio mixing will impact visuals or UI performance.</p>
*
* <p>Sounds can be looped by setting a non-zero loop value. A value of -1
- * causes the sound to loop forever. In this case, the application must
+ * causes the sound to loop forever. In this case, the application must
* explicitly call the stop() function to stop the sound. Any other non-zero
* value will cause the sound to repeat the specified number of times, e.g.
* a value of 3 causes the sound to play a total of 4 times.</p>
@@ -101,7 +101,7 @@
* <p>Note that since streams can be stopped due to resource constraints, the
* streamID is a reference to a particular instance of a stream. If the stream
* is stopped to allow a higher priority stream to play, the stream is no
- * longer be valid. However, the application is allowed to call methods on
+ * longer valid. However, the application is allowed to call methods on
* the streamID without error. This may help simplify program logic since
* the application need not concern itself with the stream lifecycle.</p>
*
@@ -137,7 +137,7 @@
*
* @param maxStreams the maximum number of simultaneous streams for this
* SoundPool object
- * @param streamType the audio stream type as described in AudioManager
+ * @param streamType the audio stream type as described in AudioManager
* For example, game applications will normally use
* {@link AudioManager#STREAM_MUSIC}.
* @param srcQuality the sample-rate converter quality. Currently has no
@@ -213,7 +213,7 @@
* "R.raw.explosion" as the resource ID. Note that this means you cannot
* have both an "explosion.wav" and an "explosion.mp3" in the res/raw
* directory.
- *
+ *
* @param context the application context
* @param resId the resource ID
* @param priority the priority of the sound. Currently has no effect. Use
@@ -287,7 +287,7 @@
/**
* Play a sound from a sound ID.
*
- * Play the sound specified by the soundID. This is the value
+ * Play the sound specified by the soundID. This is the value
* returned by the load() function. Returns a non-zero streamID
* if successful, zero if it fails. The streamID can be used to
* further control playback. Note that calling play() may cause
@@ -509,7 +509,7 @@
}
}
- private native final int _load(FileDescriptor fd, long offset, long length, int priority);
+ private native final int _load(FileDescriptor fd, long offset, long length, int priority);
private native final int native_setup(Object weakRef, int maxStreams,
Object/*AudioAttributes*/ attributes);
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 506c294..89e2675 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -328,9 +328,13 @@
<integer name="config_showTemperatureWarning">0</integer>
<!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
- If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
+ If < 0, uses the value from
+ HardwarePropertiesManager#getDeviceTemperatures - config_warningTemperatureTolerance. -->
<integer name="config_warningTemperature">-1</integer>
+ <!-- Fudge factor for how much below the shutdown temp to show the warning. -->
+ <integer name="config_warningTemperatureTolerance">2</integer>
+
<!-- Accessibility actions -->
<item type="id" name="action_split_task_to_left" />
<item type="id" name="action_split_task_to_right" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d668a41..69ccb67 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -163,7 +163,7 @@
<string name="usb_debugging_secondary_user_title">USB debugging not allowed</string>
<!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
- <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, please switch to an Admin user.</string>
+ <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
<!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
on a phone). [CHAR LIMIT=25] -->
@@ -1904,7 +1904,7 @@
<string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
<!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
- <string name="pip_menu_title">Picture in picture menu</string>
+ <string name="pip_menu_title">Menu</string>
<!-- PiP BTW notification title. [CHAR LIMIT=50] -->
<string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 32775fe..669594b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -646,13 +646,6 @@
return mStrongAuthTracker;
}
- public void reportSuccessfulStrongAuthUnlockAttempt() {
- if (mFpm != null) {
- byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
- mFpm.resetTimeout(token);
- }
- }
-
private void notifyStrongAuthStateChanged(int userId) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 9c1cb4e..ecc2111 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -39,6 +39,8 @@
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.PluginManagerImpl;
import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.power.PowerNotificationWarnings;
+import com.android.systemui.power.PowerUI;
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -296,6 +298,8 @@
mProviders.put(PluginActivityManager.class,
() -> new PluginActivityManager(mContext, getDependency(PluginManager.class)));
+ mProviders.put(PowerUI.WarningsUI.class, () -> new PowerNotificationWarnings(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6777ea2..e3eaadd 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -203,7 +203,7 @@
return Math.max(1 - progress, 0);
}
- return Math.min(0, Math.max(1, progress / SWIPE_PROGRESS_FADE_END));
+ return 1f - Math.max(0, Math.min(1, progress / SWIPE_PROGRESS_FADE_END));
}
private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 302bc2d..d374d68 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -64,17 +64,13 @@
createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
handler, wakeLock, machine),
createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
- createDozeScreenState(wrappedService),
+ new DozeScreenState(wrappedService, handler),
createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler),
});
return machine;
}
- private DozeMachine.Part createDozeScreenState(DozeMachine.Service service) {
- return new DozeScreenState(service);
- }
-
private DozeMachine.Part createDozeScreenBrightness(Context context,
DozeMachine.Service service, SensorManager sensorManager, DozeHost host,
Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 846ec27..63f5d97 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -16,7 +16,7 @@
package com.android.systemui.doze;
-import android.content.Context;
+import android.os.Handler;
import android.view.Display;
/**
@@ -24,16 +24,46 @@
*/
public class DozeScreenState implements DozeMachine.Part {
private final DozeMachine.Service mDozeService;
+ private final Handler mHandler;
+ private int mPendingScreenState = Display.STATE_UNKNOWN;
+ private Runnable mApplyPendingScreenState = this::applyPendingScreenState;
- public DozeScreenState(DozeMachine.Service service) {
+ public DozeScreenState(DozeMachine.Service service, Handler handler) {
mDozeService = service;
+ mHandler = handler;
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState();
+ if (screenState == Display.STATE_UNKNOWN) {
+ // We'll keep it in the existing state
+ return;
+ }
+ boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
+ if (messagePending || oldState == DozeMachine.State.INITIALIZED) {
+ // During initialization, we hide the navigation bar. That is however only applied after
+ // a traversal; setting the screen state here is immediate however, so it can happen
+ // that the screen turns on again before the navigation bar is hidden. To work around
+ // that, wait for a traversal to happen before applying the initial screen state.
+ mPendingScreenState = screenState;
+ if (!messagePending) {
+ mHandler.post(mApplyPendingScreenState);
+ }
+ return;
+ }
+ applyScreenState(screenState);
+ }
+
+ private void applyPendingScreenState() {
+ applyScreenState(mPendingScreenState);
+ mPendingScreenState = Display.STATE_UNKNOWN;
+ }
+
+ private void applyScreenState(int screenState) {
if (screenState != Display.STATE_UNKNOWN) {
mDozeService.setDozeScreenState(screenState);
+ mPendingScreenState = Display.STATE_UNKNOWN;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d132e76..4733008 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -560,9 +560,6 @@
}
tryKeyguardDone();
- if (strongAuth) {
- mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
- }
}
@Override
@@ -591,9 +588,6 @@
mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
KEYGUARD_DONE_PENDING_TIMEOUT_MS);
- if (strongAuth) {
- mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
- }
Trace.endSection();
}
@@ -1288,7 +1282,6 @@
// Without this, settings is not enabled until the lock screen first appears
setShowingLocked(false);
hideLocked();
- mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
return;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index e76276d..c29b362 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -106,10 +106,9 @@
private SystemUIDialog mHighTempDialog;
private SystemUIDialog mThermalShutdownDialog;
- public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
- StatusBar statusBar) {
+ public PowerNotificationWarnings(Context context) {
mContext = context;
- mNoMan = notificationManager;
+ mNoMan = mContext.getSystemService(NotificationManager.class);
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mReceiver.init();
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 28172b7..f378268 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -16,7 +16,6 @@
package com.android.systemui.power;
-import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -33,14 +32,17 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.StatusBar;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -84,10 +86,7 @@
mHardwarePropertiesManager = (HardwarePropertiesManager)
mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
- mWarnings = new PowerNotificationWarnings(
- mContext,
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE),
- getComponent(StatusBar.class));
+ mWarnings = Dependency.get(WarningsUI.class);
mLastConfiguration.setTo(mContext.getResources().getConfiguration());
ContentObserver obs = new ContentObserver(mHandler) {
@@ -267,13 +266,14 @@
// Get the throttling temperature. No need to check if we're not throttling.
float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
- HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
if (throttlingTemps == null
|| throttlingTemps.length == 0
|| throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
return;
}
- mThresholdTemp = throttlingTemps[0];
+ mThresholdTemp = throttlingTemps[0] -
+ resources.getInteger(R.integer.config_warningTemperatureTolerance);
}
setNextLogTime();
@@ -294,7 +294,8 @@
}
}
- private void updateTemperatureWarning() {
+ @VisibleForTesting
+ protected void updateTemperatureWarning() {
float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
HardwarePropertiesManager.TEMPERATURE_CURRENT);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7f5c595..6e631fa 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -134,6 +134,7 @@
private boolean mShowA11yStream;
private int mActiveStream;
+ private int mPrevActiveStream;
private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
@@ -626,10 +627,19 @@
}
}
- private boolean shouldBeVisibleH(VolumeRow row, boolean isActive) {
+ private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
+ boolean isActive = row == activeRow;
if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
return mShowA11yStream;
}
+
+ // if the active row is accessibility, then continue to display previous
+ // active row since accessibility is dispalyed under it
+ if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY &&
+ row.stream == mPrevActiveStream) {
+ return true;
+ }
+
return mExpanded && row.view.getVisibility() == View.VISIBLE
|| (mExpanded && (row.important || isActive))
|| !mExpanded && isActive;
@@ -643,7 +653,7 @@
// apply changes to all rows
for (final VolumeRow row : mRows) {
final boolean isActive = row == activeRow;
- final boolean shouldBeVisible = shouldBeVisibleH(row, isActive);
+ final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow);
Util.setVisOrGone(row.view, shouldBeVisible);
Util.setVisOrGone(row.header, shouldBeVisible);
if (row.view.isShown()) {
@@ -686,6 +696,7 @@
}
if (mActiveStream != state.activeStream) {
+ mPrevActiveStream = mActiveStream;
mActiveStream = state.activeStream;
updateRowsH(getActiveRow());
rescheduleTimeoutH();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 03f3c56..adb3baf 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -41,6 +41,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index e54c792..c787eff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -24,7 +24,14 @@
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Display;
@@ -41,11 +48,13 @@
DozeServiceFake mServiceFake;
DozeScreenState mScreen;
+ private ImmediateHandler mHandler;
@Before
public void setUp() throws Exception {
mServiceFake = new DozeServiceFake();
- mScreen = new DozeScreenState(mServiceFake);
+ mHandler = spy(new ImmediateHandler(Looper.getMainLooper()));
+ mScreen = new DozeScreenState(mServiceFake, mHandler);
}
@Test
@@ -95,4 +104,28 @@
assertEquals(Display.STATE_OFF, mServiceFake.screenState);
}
+ @Test
+ public void test_postedToHandler() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ verify(mHandler).sendMessageAtTime(any(), anyLong());
+ }
+
+ private static class ImmediateHandler extends Handler {
+
+ public ImmediateHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ Runnable callback = msg.getCallback();
+ if (callback != null) {
+ callback.run();
+ return false;
+ }
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index ac37d1e..7f07e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -52,8 +52,8 @@
@Before
public void setUp() throws Exception {
// Test Instance.
- mPowerNotificationWarnings = new PowerNotificationWarnings(
- mContext, mMockNotificationManager, null);
+ mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
+ mPowerNotificationWarnings = new PowerNotificationWarnings(mContext);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
new file mode 100644
index 0000000..e4734a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.power;
+
+import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN;
+import static android.os.HardwarePropertiesManager.TEMPERATURE_CURRENT;
+import static android.os.HardwarePropertiesManager.TEMPERATURE_SHUTDOWN;
+import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.HardwarePropertiesManager;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableResources;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.power.PowerUI.WarningsUI;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class PowerUITest extends SysuiTestCase {
+
+ private HardwarePropertiesManager mHardProps;
+ private WarningsUI mMockWarnings;
+ private PowerUI mPowerUI;
+
+ @Before
+ public void setup() {
+ mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
+ mHardProps = mock(HardwarePropertiesManager.class);
+ mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+ mContext.addMockSystemService(Context.HARDWARE_PROPERTIES_SERVICE, mHardProps);
+
+ createPowerUi();
+ }
+
+ @Test
+ public void testNoConfig_NoWarnings() {
+ setOverThreshold();
+ Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 0);
+ resources.addOverride(R.integer.config_warningTemperature, 55);
+
+ mPowerUI.start();
+ verify(mMockWarnings, never()).showHighTemperatureWarning();
+ }
+
+ @Test
+ public void testConfig_NoWarnings() {
+ setUnderThreshold();
+ Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+ resources.addOverride(R.integer.config_warningTemperature, 55);
+
+ mPowerUI.start();
+ verify(mMockWarnings, never()).showHighTemperatureWarning();
+ }
+
+ @Test
+ public void testConfig_Warnings() {
+ setOverThreshold();
+ Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+ resources.addOverride(R.integer.config_warningTemperature, 55);
+
+ mPowerUI.start();
+ verify(mMockWarnings).showHighTemperatureWarning();
+ }
+
+ @Test
+ public void testSettingOverrideConfig() {
+ setOverThreshold();
+ Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 0);
+ resources.addOverride(R.integer.config_warningTemperature, 55);
+
+ mPowerUI.start();
+ verify(mMockWarnings).showHighTemperatureWarning();
+ }
+
+ @Test
+ public void testShutdownBasedThreshold() {
+ int tolerance = 2;
+ Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+ TestableResources resources = mContext.getOrCreateTestableResources();
+ resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+ resources.addOverride(R.integer.config_warningTemperature, -1);
+ resources.addOverride(R.integer.config_warningTemperatureTolerance, tolerance);
+ when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_SHUTDOWN))
+ .thenReturn(new float[] { 55 + tolerance });
+
+ setCurrentTemp(54); // Below threshold.
+ mPowerUI.start();
+ verify(mMockWarnings, never()).showHighTemperatureWarning();
+
+ setCurrentTemp(56); // Above threshold.
+ mPowerUI.updateTemperatureWarning();
+ verify(mMockWarnings).showHighTemperatureWarning();
+ }
+
+ private void setCurrentTemp(float temp) {
+ when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
+ .thenReturn(new float[] { temp });
+ }
+
+ private void setOverThreshold() {
+ setCurrentTemp(50000);
+ }
+
+ private void setUnderThreshold() {
+ setCurrentTemp(5);
+ }
+
+ private void createPowerUi() {
+ mPowerUI = new PowerUI();
+ mPowerUI.mContext = mContext;
+ mPowerUI.mComponents = mContext.getComponents();
+ }
+}
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index d93bdc9..8503768 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -98,6 +98,13 @@
}
/**
+ * @return whether log is enabled or not.
+ */
+ public boolean enabled() {
+ return false;
+ }
+
+ /**
* Actual implementation which is only used on userdebug/eng builds (by default).
*/
private static class RotatingFileLogger extends SyncLogger {
@@ -134,6 +141,11 @@
mLogPath = new File(Environment.getDataSystemDirectory(), "syncmanager-log");
}
+ @Override
+ public boolean enabled() {
+ return true;
+ }
+
private void handleException(String message, Exception e) {
if (!mErrorShown) {
Slog.e(TAG, message, e);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3e05d50..f41aa5f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -58,6 +58,7 @@
import android.net.NetworkInfo;
import android.net.TrafficStats;
import android.os.BatteryStats;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -461,6 +462,7 @@
continue;
}
if (opx.key.equals(opy.key)) {
+ mLogger.log("Removing duplicate sync: ", opy);
mJobScheduler.cancel(opy.jobId);
}
}
@@ -473,25 +475,57 @@
if (mJobScheduler != null) {
return;
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "initializing JobScheduler object.");
- }
- mJobScheduler = (JobScheduler) mContext.getSystemService(
- Context.JOB_SCHEDULER_SERVICE);
- mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
- // Get all persisted syncs from JobScheduler
- List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
- for (JobInfo job : pendingJobs) {
- SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
- if (op != null) {
- if (!op.isPeriodic) {
- // Set the pending status of this EndPoint to true. Pending icon is
- // shown on the settings activity.
- mSyncStorageEngine.markPending(op.target, true);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "initializing JobScheduler object.");
+ }
+ mJobScheduler = (JobScheduler) mContext.getSystemService(
+ Context.JOB_SCHEDULER_SERVICE);
+ mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
+ // Get all persisted syncs from JobScheduler
+ List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
+
+ int numPersistedPeriodicSyncs = 0;
+ int numPersistedOneshotSyncs = 0;
+ for (JobInfo job : pendingJobs) {
+ SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
+ if (op != null) {
+ if (op.isPeriodic) {
+ numPersistedPeriodicSyncs++;
+ } else {
+ numPersistedOneshotSyncs++;
+ // Set the pending status of this EndPoint to true. Pending icon is
+ // shown on the settings activity.
+ mSyncStorageEngine.markPending(op.target, true);
+ }
}
}
+ if (mLogger.enabled()) {
+ mLogger.log("Connected to JobScheduler: "
+ + numPersistedPeriodicSyncs + " periodic syncs "
+ + numPersistedOneshotSyncs + " oneshot syncs.");
+ }
+ cleanupJobs();
+
+ if ((numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
+ Slog.wtf(TAG, "Device booted with no persisted periodic syncs.");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- cleanupJobs();
+ }
+
+ /**
+ * @return whether the device most likely has some periodic syncs.
+ */
+ private boolean likelyHasPeriodicSyncs() {
+ try {
+ return AccountManager.get(mContext).getAccountsByType("com.google").length > 0;
+ } catch (Throwable th) {
+ // Just in case.
+ }
+ return false;
}
private JobScheduler getJobScheduler() {
@@ -1085,11 +1119,13 @@
}
private void removeSyncsForAuthority(EndPoint info) {
+ mLogger.log("removeSyncsForAuthority: ", info);
verifyJobScheduler();
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation op: ops) {
if (op.target.matchesSpec(info)) {
- getJobScheduler().cancel(op.jobId);
+ mLogger.log("canceling: ", op);
+ getJobScheduler().cancel(op.jobId);
}
}
}
@@ -1634,6 +1670,7 @@
}
private void onUserRemoved(int userId) {
+ mLogger.log("onUserRemoved: u", userId);
updateRunningAccounts(null /* Don't sync any target */);
// Clean up the storage engine database
@@ -2926,6 +2963,9 @@
Slog.v(TAG, acc.toString());
}
}
+ if (mLogger.enabled()) {
+ mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
+ }
if (mBootCompleted) {
doDatabaseCleanup();
}
@@ -2957,6 +2997,7 @@
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation op: ops) {
if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
+ mLogger.log("canceling: ", op);
getJobScheduler().cancel(op.jobId);
}
}
@@ -3075,6 +3116,7 @@
"removePeriodicSyncInternalH");
runSyncFinishedOrCanceledH(null, asc);
}
+ mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
getJobScheduler().cancel(op.jobId);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index c6ea72f..c672949 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -561,6 +561,7 @@
mDeviceProvisionedObserver.onSystemReady();
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
+ mStrongAuth.systemReady();
}
private void migrateOldData() {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 0966153..542b929 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -27,6 +27,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
@@ -64,6 +65,7 @@
private final Context mContext;
private AlarmManager mAlarmManager;
+ private FingerprintManager mFingerprintManager;
public LockSettingsStrongAuth(Context context) {
mContext = context;
@@ -71,6 +73,10 @@
mAlarmManager = context.getSystemService(AlarmManager.class);
}
+ public void systemReady() {
+ mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+ }
+
private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
@@ -188,6 +194,11 @@
}
public void reportSuccessfulStrongAuthUnlock(int userId) {
+ if (mFingerprintManager != null) {
+ byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
+ mFingerprintManager.resetTimeout(token);
+ }
+
final int argNotUsed = 0;
mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c8d8e03..390c45e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -554,7 +554,7 @@
{
final int pid;
final String pkg;
- final ITransientNotification callback;
+ ITransientNotification callback;
int duration;
Binder token;
@@ -571,6 +571,10 @@
this.duration = duration;
}
+ void update(ITransientNotification callback) {
+ this.callback = callback;
+ }
+
void dump(PrintWriter pw, String prefix, DumpFilter filter) {
if (filter != null && !filter.matches(pkg)) return;
pw.println(prefix + this);
@@ -1604,38 +1608,28 @@
long callingId = Binder.clearCallingIdentity();
try {
ToastRecord record;
- int index = indexOfToastLocked(pkg, callback);
- // If it's already in the queue, we update it in place, we don't
- // move it to the end of the queue.
+ int index;
+ // All packages aside from the android package can enqueue one toast at a time
+ if (!isSystemToast) {
+ index = indexOfToastPackageLocked(pkg);
+ } else {
+ index = indexOfToastLocked(pkg, callback);
+ }
+
+ // If the package already has a toast, we update its toast
+ // in the queue, we don't move it to the end of the queue.
if (index >= 0) {
record = mToastQueue.get(index);
record.update(duration);
+ record.update(callback);
} else {
- // Limit the number of toasts that any given package except the android
- // package can enqueue. Prevents DOS attacks and deals with leaks.
- if (!isSystemToast) {
- int count = 0;
- final int N = mToastQueue.size();
- for (int i=0; i<N; i++) {
- final ToastRecord r = mToastQueue.get(i);
- if (r.pkg.equals(pkg)) {
- count++;
- if (count >= MAX_PACKAGE_NOTIFICATIONS) {
- Slog.e(TAG, "Package has already posted " + count
- + " toasts. Not showing more. Package=" + pkg);
- return;
- }
- }
- }
- }
-
Binder token = new Binder();
mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
record = new ToastRecord(callingPid, pkg, callback, duration, token);
mToastQueue.add(record);
index = mToastQueue.size() - 1;
- keepProcessAliveIfNeededLocked(callingPid);
}
+ keepProcessAliveIfNeededLocked(callingPid);
// If it's at index 0, it's the current toast. It doesn't matter if it's
// new or just been updated. Call back and tell it to show itself.
// If the callback fails, this will remove it from the list, so don't
@@ -2823,7 +2817,7 @@
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted) throws RemoteException {
Preconditions.checkNotNull(listener);
- enforceSystemOrSystemUI("grant notification listener access");
+ checkCallerIsSystemOrShell();
if (!mActivityManager.isLowRamDevice()) {
mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
userId, false, granted);
@@ -2844,7 +2838,7 @@
public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
int userId, boolean granted) throws RemoteException {
Preconditions.checkNotNull(assistant);
- enforceSystemOrSystemUI("grant notification assistant access");
+ checkCallerIsSystemOrShell();
if (!mActivityManager.isLowRamDevice()) {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
@@ -4241,7 +4235,21 @@
int len = list.size();
for (int i=0; i<len; i++) {
ToastRecord r = list.get(i);
- if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+ if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @GuardedBy("mToastQueue")
+ int indexOfToastPackageLocked(String pkg)
+ {
+ ArrayList<ToastRecord> list = mToastQueue;
+ int len = list.size();
+ for (int i=0; i<len; i++) {
+ ToastRecord r = list.get(i);
+ if (r.pkg.equals(pkg)) {
return i;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2f4f5ab..698d387 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -39,6 +39,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -149,6 +150,17 @@
String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
pkg.applicationInfo, sharedLibraries);
+ // Sanity check that we do not call dexopt with inconsistent data.
+ if (paths.size() != classLoaderContexts.length) {
+ String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths();
+ throw new IllegalStateException("Inconsistent information "
+ + "between PackageParser.Package and its ApplicationInfo. "
+ + "pkg.getAllCodePaths=" + paths
+ + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath()
+ + " pkg.applicationInfo.getSplitCodePaths="
+ + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
+ }
+
int result = DEX_OPT_SKIPPED;
for (int i = 0; i < paths.size(); i++) {
// Skip paths that have no code.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 082dd2b..0ecb4e1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -274,9 +274,6 @@
@Override
public boolean handleMessage(Message msg) {
synchronized (mLock) {
- if (msg.obj != null) {
- mRemoteObserver = (IPackageInstallObserver2) msg.obj;
- }
try {
commitLocked();
} catch (PackageManagerException e) {
@@ -666,7 +663,7 @@
}
@Override
- public void commit(IntentSender statusReceiver, boolean forTransfer) {
+ public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Preconditions.checkNotNull(statusReceiver);
// Cache package manager data without the lock held
@@ -679,6 +676,10 @@
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotDestroyedLocked("commit");
+ final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
+ mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
+ mRemoteObserver = adapter.getBinder();
+
if (forTransfer) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
@@ -712,9 +713,7 @@
mActiveCount.incrementAndGet();
mCommitted = true;
- final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
- mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
- mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
+ mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}
if (!wasSealed) {
@@ -1422,8 +1421,8 @@
}
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
- IPackageInstallObserver2 observer;
- String packageName;
+ final IPackageInstallObserver2 observer;
+ final String packageName;
synchronized (mLock) {
mFinalStatus = returnCode;
mFinalMessage = msg;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 99261ad..88d7cf8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7007,22 +7007,44 @@
// Okay we found a previously set preferred or last chosen app.
// If the result set is different from when this
- // was created, we need to clear it and re-ask the
- // user their preference, if we're looking for an "always" type entry.
+ // was created, and is not a subset of the preferred set, we need to
+ // clear it and re-ask the user their preference, if we're looking for
+ // an "always" type entry.
if (always && !pa.mPref.sameSet(query)) {
- Slog.i(TAG, "Result set changed, dropping preferred activity for "
- + intent + " type " + resolvedType);
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Removing preferred activity since set changed "
- + pa.mPref.mComponent);
+ if (pa.mPref.isSuperset(query)) {
+ // some components of the set are no longer present in
+ // the query, but the preferred activity can still be reused
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Result set changed, but PreferredActivity is"
+ + " still valid as only non-preferred components"
+ + " were removed for " + intent + " type "
+ + resolvedType);
+ }
+ // remove obsolete components and re-add the up-to-date filter
+ PreferredActivity freshPa = new PreferredActivity(pa,
+ pa.mPref.mMatch,
+ pa.mPref.discardObsoleteComponents(query),
+ pa.mPref.mComponent,
+ pa.mPref.mAlways);
+ pir.removeFilter(pa);
+ pir.addFilter(freshPa);
+ changed = true;
+ } else {
+ Slog.i(TAG,
+ "Result set changed, dropping preferred activity for "
+ + intent + " type " + resolvedType);
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG, "Removing preferred activity since set changed "
+ + pa.mPref.mComponent);
+ }
+ pir.removeFilter(pa);
+ // Re-add the filter as a "last chosen" entry (!always)
+ PreferredActivity lastChosen = new PreferredActivity(
+ pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
+ pir.addFilter(lastChosen);
+ changed = true;
+ return null;
}
- pir.removeFilter(pa);
- // Re-add the filter as a "last chosen" entry (!always)
- PreferredActivity lastChosen = new PreferredActivity(
- pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
- pir.addFilter(lastChosen);
- changed = true;
- return null;
}
// Yay! Either the set matched or we're looking for the last chosen
@@ -18606,36 +18628,6 @@
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
}
-
- // dexopt can take some time to complete, so, for instant apps, we skip this
- // step during installation. Instead, we'll take extra time the first time the
- // instant app starts. It's preferred to do it this way to provide continuous
- // progress to the user instead of mysteriously blocking somewhere in the
- // middle of running an instant app. The default behaviour can be overridden
- // via gservices.
- if (!instantApp || Global.getInt(
- mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
- REASON_INSTALL,
- DexoptOptions.DEXOPT_BOOT_COMPLETE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
- null /* instructionSets */,
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
- dexoptOptions);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- // Notify BackgroundDexOptService that the package has been changed.
- // If this is an update of a package which used to fail to compile,
- // BDOS will remove it from its blacklist.
- // TODO: Layering violation
- BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
@@ -18643,6 +18635,50 @@
return;
}
+ // Verify if we need to dexopt the app.
+ //
+ // NOTE: it is *important* to call dexopt after doRename which will sync the
+ // package data from PackageParser.Package and its corresponding ApplicationInfo.
+ //
+ // We only need to dexopt if the package meets ALL of the following conditions:
+ // 1) it is not forward locked.
+ // 2) it is not on on an external ASEC container.
+ // 3) it is not an instant app or if it is then dexopt is enabled via gservices.
+ //
+ // Note that we do not dexopt instant apps by default. dexopt can take some time to
+ // complete, so we skip this step during installation. Instead, we'll take extra time
+ // the first time the instant app starts. It's preferred to do it this way to provide
+ // continuous progress to the useur instead of mysteriously blocking somewhere in the
+ // middle of running an instant app. The default behaviour can be overridden
+ // via gservices.
+ final boolean performDexopt = !forwardLocked
+ && !pkg.applicationInfo.isExternalAsec()
+ && (!instantApp || Global.getInt(mContext.getContentResolver(),
+ Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
+
+ if (performDexopt) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
+ REASON_INSTALL,
+ DexoptOptions.DEXOPT_BOOT_COMPLETE);
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ null /* instructionSets */,
+ getOrCreateCompilerPackageStats(pkg),
+ mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
+ dexoptOptions);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ // Notify BackgroundDexOptService that the package has been changed.
+ // If this is an update of a package which used to fail to compile,
+ // BackgroundDexOptService will remove it from its blacklist.
+ // TODO: Layering violation
+ BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 8e2e0cd..0f4df97 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -30,6 +30,7 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
public class PreferredComponent {
@@ -241,6 +242,54 @@
return numMatch == NS;
}
+ public boolean isSuperset(List<ResolveInfo> query) {
+ if (mSetPackages == null) {
+ return query == null;
+ }
+ if (query == null) {
+ return true;
+ }
+ final int NQ = query.size();
+ final int NS = mSetPackages.length;
+ if (NS < NQ) {
+ return false;
+ }
+ for (int i=0; i<NQ; i++) {
+ ResolveInfo ri = query.get(i);
+ ActivityInfo ai = ri.activityInfo;
+ boolean foundMatch = false;
+ for (int j=0; j<NS; j++) {
+ if (mSetPackages[j].equals(ai.packageName) && mSetClasses[j].equals(ai.name)) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (!foundMatch) return false;
+ }
+ return true;
+ }
+
+ /** Returns components from mSetPackages that are present in query. */
+ public ComponentName[] discardObsoleteComponents(List<ResolveInfo> query) {
+ if (mSetPackages == null || query == null) {
+ return new ComponentName[0];
+ }
+ final int NQ = query.size();
+ final int NS = mSetPackages.length;
+ ArrayList<ComponentName> aliveComponents = new ArrayList<>();
+ for (int i = 0; i < NQ; i++) {
+ ResolveInfo ri = query.get(i);
+ ActivityInfo ai = ri.activityInfo;
+ for (int j = 0; j < NS; j++) {
+ if (mSetPackages[j].equals(ai.packageName) && mSetClasses[j].equals(ai.name)) {
+ aliveComponents.add(new ComponentName(mSetPackages[j], mSetClasses[j]));
+ break;
+ }
+ }
+ }
+ return aliveComponents.toArray(new ComponentName[aliveComponents.size()]);
+ }
+
public void dump(PrintWriter out, String prefix, Object ident) {
out.print(prefix); out.print(
Integer.toHexString(System.identityHashCode(ident)));
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index fc00acc..b8b00af 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -99,8 +99,7 @@
} catch (Exception e) {
logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
+ " because we failed to prepare: " + e);
- destroyUserDataLI(volumeUuid, userId,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+ destroyUserDataLI(volumeUuid, userId, flags);
if (allowRecover) {
// Try one last time; if we fail again we're really in trouble
diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
index 85ea3c0..9eb2b46 100644
--- a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
+++ b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
@@ -170,6 +170,11 @@
// Track overall progress of animation by computing cropped portion of status bar.
final Rect contentInsets = mWindowSurfaceController.mAnimator.mWin.mContentInsets;
float d = contentInsets.top == 0 ? 0 : (float) crop.top / contentInsets.top;
+ if (d > 1.f) {
+ // We're running expand animation from launcher, won't compute custom bg crop here.
+ mTmpContainerRect.set(crop);
+ return;
+ }
// Compute additional offset for the background when app window is positioned not at (0,0).
// E.g. landscape with navigation bar on the left.
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 651cc7d..bf9f941 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,6 +11,7 @@
$(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \
$(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \
$(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \
+ $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 3e0bc63..ae278de 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -19,6 +19,8 @@
#include "convert.h"
+#include "regions.h"
+
#include <broadcastradio-utils/Utils.h>
#include <core_jni_helpers.h>
#include <nativehelper/JNIHelp.h>
@@ -29,8 +31,11 @@
namespace BroadcastRadio {
namespace convert {
+namespace utils = V1_1::utils;
+
using hardware::Return;
using hardware::hidl_vec;
+using regions::RegionalBandConfig;
using V1_0::Band;
using V1_0::Deemphasis;
@@ -43,6 +48,7 @@
using V1_1::ProgramSelector;
using V1_1::VendorKeyValue;
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config);
static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
static struct {
@@ -334,9 +340,10 @@
auto jSerial = make_javastr(env, prop10.serial);
bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
- // ITU_1 is the default region just because its index is 0.
- auto jBands = ArrayFromHal<V1_0::BandConfig>(env, prop10.bands, gjni.BandDescriptor.clazz,
- std::bind(BandDescriptorFromHal, _1, _2, Region::ITU_1));
+
+ auto regionalBands = regions::mapRegions(prop10.bands);
+ auto jBands = ArrayFromHal<RegionalBandConfig>(env, regionalBands,
+ gjni.BandDescriptor.clazz, BandDescriptorFromHal);
auto jSupportedProgramTypes =
prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr;
auto jSupportedIdentifierTypes =
@@ -359,32 +366,31 @@
return ModulePropertiesFromHal(env, properties.base, &properties, moduleId, serviceName);
}
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config) {
+ return BandDescriptorFromHal(env, config.bandConfig, config.region);
+}
+
static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
ALOGV("%s", __func__);
jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0;
+ ALOGW_IF(config.spacings.size() > 1, "Multiple spacings - not a regional config");
ALOGW_IF(config.spacings.size() == 0, "No channel spacing specified");
- switch (config.type) {
- case Band::FM:
- case Band::FM_HD: {
- auto& fm = config.ext.fm;
- return make_javaref(env, env->NewObject(
- gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
- region, config.type, config.lowerLimit, config.upperLimit, spacing,
- fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
- }
- case Band::AM:
- case Band::AM_HD: {
- auto& am = config.ext.am;
- return make_javaref(env, env->NewObject(
- gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
- region, config.type, config.lowerLimit, config.upperLimit, spacing,
- am.stereo));
- }
- default:
- ALOGE("Unsupported band type: %d", config.type);
- return nullptr;
+ if (utils::isFm(config.type)) {
+ auto& fm = config.ext.fm;
+ return make_javaref(env, env->NewObject(
+ gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
+ region, config.type, config.lowerLimit, config.upperLimit, spacing,
+ fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
+ } else if (utils::isAm(config.type)) {
+ auto& am = config.ext.am;
+ return make_javaref(env, env->NewObject(
+ gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
+ region, config.type, config.lowerLimit, config.upperLimit, spacing, am.stereo));
+ } else {
+ ALOGE("Unsupported band type: %d", config.type);
+ return nullptr;
}
}
@@ -394,20 +400,15 @@
auto descriptor = BandDescriptorFromHal(env, config, region);
if (descriptor == nullptr) return nullptr;
- switch (config.type) {
- case Band::FM:
- case Band::FM_HD: {
- return make_javaref(env, env->NewObject(
- gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
- }
- case Band::AM:
- case Band::AM_HD: {
- return make_javaref(env, env->NewObject(
- gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
- }
- default:
- ALOGE("Unsupported band type: %d", config.type);
- return nullptr;
+ if (utils::isFm(config.type)) {
+ return make_javaref(env, env->NewObject(
+ gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
+ } else if (utils::isAm(config.type)) {
+ return make_javaref(env, env->NewObject(
+ gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
+ } else {
+ ALOGE("Unsupported band type: %d", config.type);
+ return nullptr;
}
}
@@ -583,7 +584,7 @@
}
JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info, V1_0::Band band) {
- auto selector = V1_1::utils::make_selector(band, info.channel, info.subChannel);
+ auto selector = utils::make_selector(band, info.channel, info.subChannel);
return ProgramInfoFromHal(env, info, nullptr, selector);
}
diff --git a/services/core/jni/BroadcastRadio/regions.cpp b/services/core/jni/BroadcastRadio/regions.cpp
new file mode 100644
index 0000000..e313521
--- /dev/null
+++ b/services/core/jni/BroadcastRadio/regions.cpp
@@ -0,0 +1,196 @@
+/**
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "BroadcastRadioService.regions.jni"
+#define LOG_NDEBUG 0
+
+#include "regions.h"
+
+#include <broadcastradio-utils/Utils.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace utils = hardware::broadcastradio::V1_1::utils;
+
+using hardware::hidl_vec;
+
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+
+class RegionalBandDefinition {
+public:
+ std::vector<Region> mRegions;
+ std::vector<Band> mTypes;
+ uint32_t mLowerLimit;
+ uint32_t mUpperLimit;
+ uint32_t mSpacing;
+
+ Deemphasis mFmDeemphasis = {};
+ Rds mFmRds = Rds::NONE;
+
+ bool fitsInsideBand(const BandConfig &bandConfig) const;
+ std::vector<RegionalBandConfig> withConfig(BandConfig bandConfig) const;
+};
+
+static const RegionalBandDefinition kKnownRegionConfigs[] = {
+ {
+ { Region::ITU_1 },
+ { Band::FM },
+ 87500,
+ 108000,
+ 100,
+ Deemphasis::D50,
+ Rds::WORLD,
+ },
+ {
+ { Region::ITU_2 },
+ { Band::FM, Band::FM_HD },
+ 87900,
+ 107900,
+ 200,
+ Deemphasis::D75,
+ Rds::US,
+ },
+ {
+ { Region::OIRT },
+ { Band::FM },
+ 65800,
+ 74000,
+ 10,
+ Deemphasis::D50,
+ Rds::WORLD,
+ },
+ {
+ { Region::JAPAN },
+ { Band::FM },
+ 76000,
+ 90000,
+ 100,
+ Deemphasis::D50,
+ Rds::WORLD,
+ },
+ {
+ { Region::KOREA },
+ { Band::FM },
+ 87500,
+ 108000,
+ 100,
+ Deemphasis::D75,
+ Rds::WORLD,
+ },
+ { // AM LW
+ { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+ { Band::AM },
+ 153,
+ 279,
+ 9,
+ },
+ { // AM MW
+ { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+ { Band::AM },
+ 531,
+ 1611,
+ 9,
+ },
+ { // AM SW
+ { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+ { Band::AM },
+ 2300,
+ 26100,
+ 5,
+ },
+ { // AM LW ITU2
+ { Region::ITU_2 },
+ { Band::AM, Band::AM_HD },
+ 153,
+ 279,
+ 9,
+ },
+ { // AM MW ITU2
+ { Region::ITU_2 },
+ { Band::AM, Band::AM_HD },
+ 540,
+ 1610,
+ 10,
+ },
+ { // AM SW ITU2
+ { Region::ITU_2 },
+ { Band::AM, Band::AM_HD },
+ 2300,
+ 26100,
+ 5,
+ },
+};
+
+bool RegionalBandDefinition::fitsInsideBand(const BandConfig &bandConfig) const {
+ if (std::find(mTypes.begin(), mTypes.end(), bandConfig.type) == mTypes.end()) return false;
+ if (mLowerLimit < bandConfig.lowerLimit) return false;
+ if (mUpperLimit > bandConfig.upperLimit) return false;
+ auto&& spacings = bandConfig.spacings;
+ if (std::find(spacings.begin(), spacings.end(), mSpacing) == spacings.end()) return false;
+ if (utils::isFm(bandConfig.type)) {
+ if (0 == (mFmDeemphasis & bandConfig.ext.fm.deemphasis)) return false;
+ }
+
+ return true;
+}
+
+std::vector<RegionalBandConfig> RegionalBandDefinition::withConfig(BandConfig config) const {
+ config.lowerLimit = mLowerLimit;
+ config.upperLimit = mUpperLimit;
+ config.spacings = hidl_vec<uint32_t>({ mSpacing });
+ if (utils::isFm(config.type)) {
+ auto&& fm = config.ext.fm;
+ fm.deemphasis = mFmDeemphasis;
+ fm.rds = static_cast<Rds>(mFmRds & fm.rds);
+ }
+
+ std::vector<RegionalBandConfig> configs;
+ for (auto region : mRegions) {
+ configs.push_back({region, config});
+ }
+
+ return configs;
+}
+
+std::vector<RegionalBandConfig> mapRegions(const hidl_vec<BandConfig>& bands) {
+ ALOGV("%s", __func__);
+
+ std::vector<RegionalBandConfig> out;
+
+ for (auto&& regionalBand : kKnownRegionConfigs) {
+ for (auto&& tunerBand : bands) {
+ if (regionalBand.fitsInsideBand(tunerBand)) {
+ auto mapped = regionalBand.withConfig(tunerBand);
+ out.insert(out.end(), mapped.begin(), mapped.end());
+ }
+ }
+ }
+
+ ALOGI("Mapped %zu tuner bands to %zu regional bands", bands.size(), out.size());
+ return out;
+}
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
diff --git a/services/core/jni/BroadcastRadio/regions.h b/services/core/jni/BroadcastRadio/regions.h
new file mode 100644
index 0000000..45a32ea
--- /dev/null
+++ b/services/core/jni/BroadcastRadio/regions.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
+#define _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
+
+#include "types.h"
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace V1_0 = hardware::broadcastradio::V1_0;
+
+struct RegionalBandConfig {
+ Region region;
+ V1_0::BandConfig bandConfig;
+};
+
+std::vector<RegionalBandConfig>
+mapRegions(const hardware::hidl_vec<V1_0::BandConfig>& bands);
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
+
+#endif // _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 57fc9ce..f30d7bd 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
+import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -1464,7 +1465,11 @@
if (mExtras == null) {
mExtras = new Bundle();
}
- mExtras.putAll(extras);
+ try {
+ mExtras.putAll(extras);
+ } catch (BadParcelableException bpe) {
+ Log.w(this, "putExtras: could not unmarshal extras; exception = " + bpe);
+ }
notifyExtrasChanged();
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 68fd825..7e08f51 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -321,6 +321,7 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
@Override
public String[] getNamesForUids(int uid[]) {
throw new UnsupportedOperationException();