Merge "Update Region parcelling to use SkRegion::Iter" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index a082a23..9e96249 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4275,6 +4275,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
@@ -28574,7 +28575,6 @@
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -32153,6 +32153,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
diff --git a/api/system-current.txt b/api/system-current.txt
index e4437aa..12187dd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4407,6 +4407,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
@@ -26806,7 +26807,6 @@
field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
field public static final deprecated int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
- field public static final int REPORT_EVENT_CONTEXT_HUB = 8; // 0x8
field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
@@ -30858,7 +30858,6 @@
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -34634,6 +34633,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -34694,6 +34694,7 @@
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
field public static final java.lang.String MODE_RINGER = "mode_ringer";
field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
+ field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
diff --git a/api/test-current.txt b/api/test-current.txt
index de1496b..74c6787 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4275,6 +4275,7 @@
public class DownloadManager {
method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean);
+ method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri);
method public long enqueue(android.app.DownloadManager.Request);
method public static java.lang.Long getMaxBytesOverMobile(android.content.Context);
method public java.lang.String getMimeTypeForDownloadedFile(long);
@@ -28583,7 +28584,6 @@
field public static java.lang.String DIRECTORY_DCIM;
field public static java.lang.String DIRECTORY_DOCUMENTS;
field public static java.lang.String DIRECTORY_DOWNLOADS;
- field public static java.lang.String DIRECTORY_HOME;
field public static java.lang.String DIRECTORY_MOVIES;
field public static java.lang.String DIRECTORY_MUSIC;
field public static java.lang.String DIRECTORY_NOTIFICATIONS;
@@ -32166,6 +32166,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_SCREEN_READER_TUTORIAL = "android.settings.SCREEN_READER_TUTORIAL";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index ed4bb28..1e5f007 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1193,13 +1193,52 @@
boolean isMediaScannerScannable, String mimeType, String path, long length,
boolean showNotification) {
return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
- length, showNotification, false);
+ length, showNotification, false, null, null);
+ }
+
+ /**
+ * Adds a file to the downloads database system, so it could appear in Downloads App
+ * (and thus become eligible for management by the Downloads App).
+ * <p>
+ * It is helpful to make the file scannable by MediaScanner by setting the param
+ * isMediaScannerScannable to true. It makes the file visible in media managing
+ * applications such as Gallery App, which could be a useful purpose of using this API.
+ *
+ * @param title the title that would appear for this file in Downloads App.
+ * @param description the description that would appear for this file in Downloads App.
+ * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files
+ * scanned by MediaScanner appear in the applications used to view media (for example,
+ * Gallery app).
+ * @param mimeType mimetype of the file.
+ * @param path absolute pathname to the file. The file should be world-readable, so that it can
+ * be managed by the Downloads App and any other app that is used to read it (for example,
+ * Gallery app to display the file, if the file contents represent a video/image).
+ * @param length length of the downloaded file
+ * @param showNotification true if a notification is to be sent, false otherwise
+ * @param uri the original HTTP URI of the download
+ * @param referer the HTTP Referer for the download
+ * @return an ID for the download entry added to the downloads app, unique across the system
+ * This ID is used to make future calls related to this download.
+ */
+ public long addCompletedDownload(String title, String description,
+ boolean isMediaScannerScannable, String mimeType, String path, long length,
+ boolean showNotification, Uri uri, Uri referer) {
+ return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
+ length, showNotification, false, uri, referer);
}
/** {@hide} */
public long addCompletedDownload(String title, String description,
boolean isMediaScannerScannable, String mimeType, String path, long length,
boolean showNotification, boolean allowWrite) {
+ return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
+ length, showNotification, allowWrite, null, null);
+ }
+
+ /** {@hide} */
+ public long addCompletedDownload(String title, String description,
+ boolean isMediaScannerScannable, String mimeType, String path, long length,
+ boolean showNotification, boolean allowWrite, Uri uri, Uri referer) {
// make sure the input args are non-null/non-zero
validateArgumentIsNonEmpty("title", title);
validateArgumentIsNonEmpty("description", description);
@@ -1210,10 +1249,18 @@
}
// if there is already an entry with the given path name in downloads.db, return its id
- Request request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD)
- .setTitle(title)
+ Request request;
+ if (uri != null) {
+ request = new Request(uri);
+ } else {
+ request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD);
+ }
+ request.setTitle(title)
.setDescription(description)
.setMimeType(mimeType);
+ if (referer != null) {
+ request.addRequestHeader("Referer", referer.toString());
+ }
ContentValues values = request.toContentValues(null);
values.put(Downloads.Impl.COLUMN_DESTINATION,
Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index bed91ec..cd8f126 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -376,7 +376,13 @@
* AppWidget provider. Will animate into these new views as needed
*/
public void updateAppWidget(RemoteViews remoteViews) {
+ applyRemoteViews(remoteViews);
+ }
+ /**
+ * @hide
+ */
+ protected void applyRemoteViews(RemoteViews remoteViews) {
if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
boolean recycled = false;
@@ -573,8 +579,9 @@
/**
* Build a {@link Context} cloned into another package name, usually for the
* purposes of reading remote resources.
+ * @hide
*/
- private Context getRemoteContext() {
+ protected Context getRemoteContext() {
try {
// Return if cloned successfully, otherwise default
return mContext.createApplicationContext(
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 59bf293..70f9cc5 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -476,11 +476,6 @@
public static String DIRECTORY_DOCUMENTS = "Documents";
/**
- * Standard directory in which user managed files are stored.
- */
- public static String DIRECTORY_HOME = "Home";
-
- /**
* List of standard storage directories.
* <p>
* Each of its values have its own constant:
@@ -495,7 +490,6 @@
* <li>{@link #DIRECTORY_DOWNLOADS}
* <li>{@link #DIRECTORY_DCIM}
* <li>{@link #DIRECTORY_DOCUMENTS}
- * <li>{@link #DIRECTORY_HOME}
* </ul>
* @hide
*/
@@ -509,8 +503,7 @@
DIRECTORY_MOVIES,
DIRECTORY_DOWNLOADS,
DIRECTORY_DCIM,
- DIRECTORY_DOCUMENTS,
- DIRECTORY_HOME
+ DIRECTORY_DOCUMENTS
};
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3169bf4..5ab2b00 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -201,6 +201,21 @@
"android.settings.ACCESSIBILITY_SETTINGS";
/**
+ * Activity Action: Launch the screen reader tutorial.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SCREEN_READER_TUTORIAL =
+ "android.settings.SCREEN_READER_TUTORIAL";
+
+
+ /**
* Activity Action: Show settings to control access to usage information.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -6716,6 +6731,16 @@
public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
/**
+ * Whether to disable the automatic scheduling of system updates.
+ * 1 = system updates won't be automatically scheduled (will always
+ * present notification instead).
+ * 0 = system updates will be automatically scheduled. (default)
+ * @hide
+ */
+ @SystemApi
+ public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
+
+ /**
* Whether the package manager should send package verification broadcasts for verifiers to
* review apps prior to installation.
* 1 = request apps to be verified prior to installation, if a verifier exists.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 96853e0..6dc5ccc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1606,10 +1606,6 @@
frame.height() < desiredWindowHeight && frame.height() != mHeight));
windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM;
- // If the backdrop frame doesn't equal to a frame, we are starting a resize operation, so
- // force it to be resized.
- windowShouldResize |= !mPendingBackDropFrame.equals(mWinFrame);
-
// If the activity was just relaunched, it might have unfrozen the task bounds (while
// relaunching), so we need to force a call into window manager to pick up the latest
// bounds.
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 5953a98..8278c5a 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -18,11 +18,13 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import android.Manifest;
+import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +36,9 @@
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
@@ -74,7 +79,7 @@
private RemoteViewsAdapterServiceConnection mServiceConnection;
private WeakReference<RemoteAdapterConnectionCallback> mCallback;
private OnClickHandler mRemoteViewsOnClickHandler;
- private FixedSizeRemoteViewsCache mCache;
+ private final FixedSizeRemoteViewsCache mCache;
private int mVisibleWindowLowerBound;
private int mVisibleWindowUpperBound;
@@ -92,13 +97,10 @@
// We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data
// structures;
- private static final HashMap<RemoteViewsCacheKey,
- FixedSizeRemoteViewsCache> sCachedRemoteViewsCaches
- = new HashMap<RemoteViewsCacheKey,
- FixedSizeRemoteViewsCache>();
+ private static final HashMap<RemoteViewsCacheKey, FixedSizeRemoteViewsCache>
+ sCachedRemoteViewsCaches = new HashMap<>();
private static final HashMap<RemoteViewsCacheKey, Runnable>
- sRemoteViewsCacheRemoveRunnables
- = new HashMap<RemoteViewsCacheKey, Runnable>();
+ sRemoteViewsCacheRemoveRunnables = new HashMap<>();
private static HandlerThread sCacheRemovalThread;
private static Handler sCacheRemovalQueue;
@@ -286,9 +288,12 @@
* A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when
* they are loaded.
*/
- private static class RemoteViewsFrameLayout extends FrameLayout {
- public RemoteViewsFrameLayout(Context context) {
+ private static class RemoteViewsFrameLayout extends AppWidgetHostView {
+ private final FixedSizeRemoteViewsCache mCache;
+
+ public RemoteViewsFrameLayout(Context context, FixedSizeRemoteViewsCache cache) {
super(context);
+ mCache = cache;
}
/**
@@ -297,13 +302,24 @@
* successfully.
*/
public void onRemoteViewsLoaded(RemoteViews view, OnClickHandler handler) {
- try {
- // Remove all the children of this layout first
- removeAllViews();
- addView(view.apply(getContext(), this, handler));
- } catch (Exception e) {
- Log.e(TAG, "Failed to apply RemoteViews.");
- }
+ setOnClickHandler(handler);
+ applyRemoteViews(view);
+ }
+
+ @Override
+ protected View getDefaultView() {
+ return mCache.getMetaData().createDefaultLoadingView(this);
+ }
+
+ @Override
+ protected Context getRemoteContext() {
+ return null;
+ }
+
+ @Override
+ protected View getErrorView() {
+ // Use the default loading view as the error view.
+ return getDefaultView();
}
}
@@ -312,29 +328,21 @@
* adapter that have not yet had their RemoteViews loaded.
*/
private class RemoteViewsFrameLayoutRefSet {
- private HashMap<Integer, LinkedList<RemoteViewsFrameLayout>> mReferences;
- private HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
- mViewToLinkedList;
-
- public RemoteViewsFrameLayoutRefSet() {
- mReferences = new HashMap<Integer, LinkedList<RemoteViewsFrameLayout>>();
- mViewToLinkedList =
- new HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>();
- }
+ private final SparseArray<LinkedList<RemoteViewsFrameLayout>> mReferences =
+ new SparseArray<>();
+ private final HashMap<RemoteViewsFrameLayout, LinkedList<RemoteViewsFrameLayout>>
+ mViewToLinkedList = new HashMap<>();
/**
* Adds a new reference to a RemoteViewsFrameLayout returned by the adapter.
*/
public void add(int position, RemoteViewsFrameLayout layout) {
- final Integer pos = position;
- LinkedList<RemoteViewsFrameLayout> refs;
+ LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
// Create the list if necessary
- if (mReferences.containsKey(pos)) {
- refs = mReferences.get(pos);
- } else {
+ if (refs == null) {
refs = new LinkedList<RemoteViewsFrameLayout>();
- mReferences.put(pos, refs);
+ mReferences.put(position, refs);
}
mViewToLinkedList.put(layout, refs);
@@ -349,10 +357,9 @@
public void notifyOnRemoteViewsLoaded(int position, RemoteViews view) {
if (view == null) return;
- final Integer pos = position;
- if (mReferences.containsKey(pos)) {
+ final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(position);
+ if (refs != null) {
// Notify all the references for that position of the newly loaded RemoteViews
- final LinkedList<RemoteViewsFrameLayout> refs = mReferences.get(pos);
for (final RemoteViewsFrameLayout ref : refs) {
ref.onRemoteViewsLoaded(view, mRemoteViewsOnClickHandler);
if (mViewToLinkedList.containsKey(ref)) {
@@ -361,7 +368,7 @@
}
refs.clear();
// Remove this set from the original mapping
- mReferences.remove(pos);
+ mReferences.remove(position);
}
}
@@ -402,7 +409,7 @@
int mFirstViewHeight;
// A mapping from type id to a set of unique type ids
- private final HashMap<Integer, Integer> mTypeIdIndexMap = new HashMap<Integer, Integer>();
+ private final SparseIntArray mTypeIdIndexMap = new SparseIntArray();
public RemoteViewsMetaData() {
reset();
@@ -438,82 +445,47 @@
}
public int getMappedViewType(int typeId) {
- if (mTypeIdIndexMap.containsKey(typeId)) {
- return mTypeIdIndexMap.get(typeId);
- } else {
+ int mappedTypeId = mTypeIdIndexMap.get(typeId, -1);
+ if (mappedTypeId == -1) {
// We +1 because the loading view always has view type id of 0
- int incrementalTypeId = mTypeIdIndexMap.size() + 1;
- mTypeIdIndexMap.put(typeId, incrementalTypeId);
- return incrementalTypeId;
+ mappedTypeId = mTypeIdIndexMap.size() + 1;
+ mTypeIdIndexMap.put(typeId, mappedTypeId);
}
+ return mappedTypeId;
}
public boolean isViewTypeInRange(int typeId) {
int mappedType = getMappedViewType(typeId);
- if (mappedType >= viewTypeCount) {
- return false;
- } else {
- return true;
- }
+ return (mappedType < viewTypeCount);
}
- private RemoteViewsFrameLayout createLoadingView(int position, View convertView,
- ViewGroup parent, Object lock, LayoutInflater layoutInflater, OnClickHandler
- handler) {
- // Create and return a new FrameLayout, and setup the references for this position
+ /**
+ * Creates a default loading view. Uses the size of the first row as a guide for the
+ * size of the loading view.
+ */
+ private synchronized View createDefaultLoadingView(ViewGroup parent) {
final Context context = parent.getContext();
- RemoteViewsFrameLayout layout = new RemoteViewsFrameLayout(context);
-
- // Create a new loading view
- synchronized (lock) {
- boolean customLoadingViewAvailable = false;
-
- if (mUserLoadingView != null) {
- // Try to inflate user-specified loading view
- try {
- View loadingView = mUserLoadingView.apply(parent.getContext(), parent,
- handler);
- loadingView.setTagInternal(com.android.internal.R.id.rowTypeId,
- new Integer(0));
- layout.addView(loadingView);
- customLoadingViewAvailable = true;
- } catch (Exception e) {
- Log.w(TAG, "Error inflating custom loading view, using default loading" +
- "view instead", e);
- }
+ if (mFirstViewHeight < 0) {
+ try {
+ View firstView = mFirstView.apply(parent.getContext(), parent);
+ firstView.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mFirstViewHeight = firstView.getMeasuredHeight();
+ } catch (Exception e) {
+ float density = context.getResources().getDisplayMetrics().density;
+ mFirstViewHeight = Math.round(sDefaultLoadingViewHeight * density);
+ Log.w(TAG, "Error inflating first RemoteViews" + e);
}
- if (!customLoadingViewAvailable) {
- // A default loading view
- // Use the size of the first row as a guide for the size of the loading view
- if (mFirstViewHeight < 0) {
- try {
- View firstView = mFirstView.apply(parent.getContext(), parent, handler);
- firstView.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mFirstViewHeight = firstView.getMeasuredHeight();
- mFirstView = null;
- } catch (Exception e) {
- float density = context.getResources().getDisplayMetrics().density;
- mFirstViewHeight = (int)
- Math.round(sDefaultLoadingViewHeight * density);
- mFirstView = null;
- Log.w(TAG, "Error inflating first RemoteViews" + e);
- }
- }
-
- // Compose the loading view text
- TextView loadingTextView = (TextView) layoutInflater.inflate(
- com.android.internal.R.layout.remote_views_adapter_default_loading_view,
- layout, false);
- loadingTextView.setHeight(mFirstViewHeight);
- loadingTextView.setTag(new Integer(0));
-
- layout.addView(loadingTextView);
- }
+ mFirstView = null;
}
- return layout;
+ // Compose the loading view text
+ TextView loadingTextView = (TextView) LayoutInflater.from(context).inflate(
+ com.android.internal.R.layout.remote_views_adapter_default_loading_view,
+ parent, false);
+ loadingTextView.setHeight(mFirstViewHeight);
+ return loadingTextView;
}
}
@@ -548,8 +520,8 @@
// The meta data objects are made final so that they can be locked on independently
// of the FixedSizeRemoteViewsCache. If we ever lock on both meta data objects, it is in
// the order mTemporaryMetaData followed by mMetaData.
- private final RemoteViewsMetaData mMetaData;
- private final RemoteViewsMetaData mTemporaryMetaData;
+ private final RemoteViewsMetaData mMetaData = new RemoteViewsMetaData();
+ private final RemoteViewsMetaData mTemporaryMetaData = new RemoteViewsMetaData();
// The cache/mapping of position to RemoteViewsMetaData. This set is guaranteed to be
// greater than or equal to the set of RemoteViews.
@@ -558,22 +530,20 @@
// the heavy RemoteViews around. The RemoteViews cache is trimmed to fixed constraints wrt.
// memory and size, but this metadata cache will retain information until the data at the
// position is guaranteed as not being necessary any more (usually on notifyDataSetChanged).
- private HashMap<Integer, RemoteViewsIndexMetaData> mIndexMetaData;
+ private final SparseArray<RemoteViewsIndexMetaData> mIndexMetaData = new SparseArray<>();
// The cache of actual RemoteViews, which may be pruned if the cache gets too large, or uses
// too much memory.
- private HashMap<Integer, RemoteViews> mIndexRemoteViews;
+ private final SparseArray<RemoteViews> mIndexRemoteViews = new SparseArray<>();
- // The set of indices that have been explicitly requested by the collection view
- private HashSet<Integer> mRequestedIndices;
+ // An array of indices to load, Indices which are explicitely requested are set to true,
+ // and those determined by the preloading algorithm to prefetch are set to false.
+ private final SparseBooleanArray mIndicesToLoad = new SparseBooleanArray();
// We keep a reference of the last requested index to determine which item to prune the
// farthest items from when we hit the memory limit
private int mLastRequestedIndex;
- // The set of indices to load, including those explicitly requested, as well as those
- // determined by the preloading algorithm to be prefetched
- private HashSet<Integer> mLoadIndices;
// The lower and upper bounds of the preloaded range
private int mPreloadLowerBound;
@@ -584,8 +554,8 @@
// The maxCountSlack is used to determine if a new position in the cache to be loaded is
// sufficiently ouside the old set, prompting a shifting of the "window" of items to be
// preloaded.
- private int mMaxCount;
- private int mMaxCountSlack;
+ private final int mMaxCount;
+ private final int mMaxCountSlack;
private static final float sMaxCountSlackPercent = 0.75f;
private static final int sMaxMemoryLimitInBytes = 2 * 1024 * 1024;
@@ -594,17 +564,10 @@
mMaxCountSlack = Math.round(sMaxCountSlackPercent * (mMaxCount / 2));
mPreloadLowerBound = 0;
mPreloadUpperBound = -1;
- mMetaData = new RemoteViewsMetaData();
- mTemporaryMetaData = new RemoteViewsMetaData();
- mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>();
- mIndexRemoteViews = new HashMap<Integer, RemoteViews>();
- mRequestedIndices = new HashSet<Integer>();
mLastRequestedIndex = -1;
- mLoadIndices = new HashSet<Integer>();
}
- public void insert(int position, RemoteViews v, long itemId,
- ArrayList<Integer> visibleWindow) {
+ public void insert(int position, RemoteViews v, long itemId, int[] visibleWindow) {
// Trim the cache if we go beyond the count
if (mIndexRemoteViews.size() >= mMaxCount) {
mIndexRemoteViews.remove(getFarthestPositionFrom(position, visibleWindow));
@@ -630,8 +593,8 @@
}
// Update the metadata cache
- if (mIndexMetaData.containsKey(position)) {
- final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
+ final RemoteViewsIndexMetaData metaData = mIndexMetaData.get(position);
+ if (metaData != null) {
metaData.set(v, itemId);
} else {
mIndexMetaData.put(position, new RemoteViewsIndexMetaData(v, itemId));
@@ -646,16 +609,10 @@
return mTemporaryMetaData;
}
public RemoteViews getRemoteViewsAt(int position) {
- if (mIndexRemoteViews.containsKey(position)) {
- return mIndexRemoteViews.get(position);
- }
- return null;
+ return mIndexRemoteViews.get(position);
}
public RemoteViewsIndexMetaData getMetaDataAt(int position) {
- if (mIndexMetaData.containsKey(position)) {
- return mIndexMetaData.get(position);
- }
- return null;
+ return mIndexMetaData.get(position);
}
public void commitTemporaryMetaData() {
@@ -669,8 +626,8 @@
private int getRemoteViewsBitmapMemoryUsage() {
// Calculate the memory usage of all the RemoteViews bitmaps being cached
int mem = 0;
- for (Integer i : mIndexRemoteViews.keySet()) {
- final RemoteViews v = mIndexRemoteViews.get(i);
+ for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
+ final RemoteViews v = mIndexRemoteViews.valueAt(i);
if (v != null) {
mem += v.estimateMemoryUsage();
}
@@ -678,24 +635,25 @@
return mem;
}
- private int getFarthestPositionFrom(int pos, ArrayList<Integer> visibleWindow) {
+ private int getFarthestPositionFrom(int pos, int[] visibleWindow) {
// Find the index farthest away and remove that
int maxDist = 0;
int maxDistIndex = -1;
int maxDistNotVisible = 0;
int maxDistIndexNotVisible = -1;
- for (int i : mIndexRemoteViews.keySet()) {
- int dist = Math.abs(i-pos);
- if (dist > maxDistNotVisible && !visibleWindow.contains(i)) {
+ for (int i = mIndexRemoteViews.size() - 1; i >= 0; i--) {
+ int index = mIndexRemoteViews.keyAt(i);
+ int dist = Math.abs(index-pos);
+ if (dist > maxDistNotVisible && Arrays.binarySearch(visibleWindow, index) < 0) {
// maxDistNotVisible/maxDistIndexNotVisible will store the index of the
// farthest non-visible position
- maxDistIndexNotVisible = i;
+ maxDistIndexNotVisible = index;
maxDistNotVisible = dist;
}
if (dist >= maxDist) {
// maxDist/maxDistIndex will store the index of the farthest position
// regardless of whether it is visible or not
- maxDistIndex = i;
+ maxDistIndex = index;
maxDist = dist;
}
}
@@ -707,9 +665,8 @@
public void queueRequestedPositionToLoad(int position) {
mLastRequestedIndex = position;
- synchronized (mLoadIndices) {
- mRequestedIndices.add(position);
- mLoadIndices.add(position);
+ synchronized (mIndicesToLoad) {
+ mIndicesToLoad.put(position, true);
}
}
public boolean queuePositionsToBePreloadedFromRequestedPosition(int position) {
@@ -725,11 +682,13 @@
synchronized (mMetaData) {
count = mMetaData.count;
}
- synchronized (mLoadIndices) {
- mLoadIndices.clear();
-
- // Add all the requested indices
- mLoadIndices.addAll(mRequestedIndices);
+ synchronized (mIndicesToLoad) {
+ // Remove all indices which have not been previously requested.
+ for (int i = mIndicesToLoad.size() - 1; i >= 0; i--) {
+ if (!mIndicesToLoad.valueAt(i)) {
+ mIndicesToLoad.removeAt(i);
+ }
+ }
// Add all the preload indices
int halfMaxCount = mMaxCount / 2;
@@ -738,43 +697,40 @@
int effectiveLowerBound = Math.max(0, mPreloadLowerBound);
int effectiveUpperBound = Math.min(mPreloadUpperBound, count - 1);
for (int i = effectiveLowerBound; i <= effectiveUpperBound; ++i) {
- mLoadIndices.add(i);
+ if (mIndexRemoteViews.indexOfKey(i) < 0 && !mIndicesToLoad.get(i)) {
+ // If the index has not been requested, and has not been loaded.
+ mIndicesToLoad.put(i, false);
+ }
}
-
- // But remove all the indices that have already been loaded and are cached
- mLoadIndices.removeAll(mIndexRemoteViews.keySet());
}
return true;
}
- /** Returns the next index to load, and whether that index was directly requested or not */
- public int[] getNextIndexToLoad() {
+ /** Returns the next index to load */
+ public int getNextIndexToLoad() {
// We try and prioritize items that have been requested directly, instead
// of items that are loaded as a result of the caching mechanism
- synchronized (mLoadIndices) {
+ synchronized (mIndicesToLoad) {
// Prioritize requested indices to be loaded first
- if (!mRequestedIndices.isEmpty()) {
- Integer i = mRequestedIndices.iterator().next();
- mRequestedIndices.remove(i);
- mLoadIndices.remove(i);
- return new int[]{i.intValue(), 1};
+ int index = mIndicesToLoad.indexOfValue(true);
+ if (index < 0) {
+ // Otherwise, preload other indices as necessary
+ index = mIndicesToLoad.indexOfValue(false);
}
-
- // Otherwise, preload other indices as necessary
- if (!mLoadIndices.isEmpty()) {
- Integer i = mLoadIndices.iterator().next();
- mLoadIndices.remove(i);
- return new int[]{i.intValue(), 0};
+ if (index < 0) {
+ return -1;
+ } else {
+ int key = mIndicesToLoad.keyAt(index);
+ mIndicesToLoad.removeAt(index);
+ return key;
}
-
- return new int[]{-1, 0};
}
}
public boolean containsRemoteViewAt(int position) {
- return mIndexRemoteViews.containsKey(position);
+ return mIndexRemoteViews.indexOfKey(position) >= 0;
}
public boolean containsMetaDataAt(int position) {
- return mIndexMetaData.containsKey(position);
+ return mIndexMetaData.indexOfKey(position) >= 0;
}
public void reset() {
@@ -787,9 +743,8 @@
mLastRequestedIndex = -1;
mIndexRemoteViews.clear();
mIndexMetaData.clear();
- synchronized (mLoadIndices) {
- mRequestedIndices.clear();
- mLoadIndices.clear();
+ synchronized (mIndicesToLoad) {
+ mIndicesToLoad.clear();
}
}
}
@@ -942,8 +897,7 @@
// Get the next index to load
int position = -1;
synchronized (mCache) {
- int[] res = mCache.getNextIndexToLoad();
- position = res[0];
+ position = mCache.getNextIndexToLoad();
}
if (position > -1) {
// Load the item, and notify any existing RemoteViewsFrameLayouts
@@ -1048,7 +1002,7 @@
}
synchronized (mCache) {
if (viewTypeInRange) {
- ArrayList<Integer> visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
+ int[] visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
mVisibleWindowUpperBound, cacheCount);
// Cache the RemoteViews we loaded
mCache.insert(position, remoteViews, itemId, visibleWindow);
@@ -1117,21 +1071,6 @@
}
/**
- * Returns the item type id for the specified convert view. Returns -1 if the convert view
- * is invalid.
- */
- private int getConvertViewTypeId(View convertView) {
- int typeId = -1;
- if (convertView != null) {
- Object tag = convertView.getTag(com.android.internal.R.id.rowTypeId);
- if (tag != null) {
- typeId = (Integer) tag;
- }
- }
- return typeId;
- }
-
- /**
* This method allows an AdapterView using this Adapter to provide information about which
* views are currently being displayed. This allows for certain optimizations and preloading
* which wouldn't otherwise be possible.
@@ -1145,7 +1084,8 @@
// "Request" an index so that we can queue it for loading, initiate subsequent
// preloading, etc.
synchronized (mCache) {
- boolean isInCache = mCache.containsRemoteViewAt(position);
+ RemoteViews rv = mCache.getRemoteViewsAt(position);
+ boolean isInCache = (rv != null);
boolean isConnected = mServiceConnection.isConnected();
boolean hasNewItems = false;
@@ -1162,75 +1102,23 @@
hasNewItems = mCache.queuePositionsToBePreloadedFromRequestedPosition(position);
}
+ final RemoteViewsFrameLayout layout =
+ (convertView instanceof RemoteViewsFrameLayout)
+ ? (RemoteViewsFrameLayout) convertView
+ : new RemoteViewsFrameLayout(parent.getContext(), mCache);
if (isInCache) {
- View convertViewChild = null;
- int convertViewTypeId = 0;
- RemoteViewsFrameLayout layout = null;
-
- if (convertView instanceof RemoteViewsFrameLayout) {
- layout = (RemoteViewsFrameLayout) convertView;
- convertViewChild = layout.getChildAt(0);
- convertViewTypeId = getConvertViewTypeId(convertViewChild);
- }
-
- // Second, we try and retrieve the RemoteViews from the cache, returning a loading
- // view and queueing it to be loaded if it has not already been loaded.
- Context context = parent.getContext();
- RemoteViews rv = mCache.getRemoteViewsAt(position);
- RemoteViewsIndexMetaData indexMetaData = mCache.getMetaDataAt(position);
- int typeId = indexMetaData.typeId;
-
- try {
- // Reuse the convert view where possible
- if (layout != null) {
- if (convertViewTypeId == typeId) {
- rv.reapply(context, convertViewChild, mRemoteViewsOnClickHandler);
- return layout;
- }
- layout.removeAllViews();
- } else {
- layout = new RemoteViewsFrameLayout(context);
- }
-
- // Otherwise, create a new view to be returned
- View newView = rv.apply(context, parent, mRemoteViewsOnClickHandler);
- newView.setTagInternal(com.android.internal.R.id.rowTypeId,
- new Integer(typeId));
- layout.addView(newView);
- return layout;
-
- } catch (Exception e){
- // We have to make sure that we successfully inflated the RemoteViews, if not
- // we return the loading view instead.
- Log.w(TAG, "Error inflating RemoteViews at position: " + position + ", using" +
- "loading view instead" + e);
-
- RemoteViewsFrameLayout loadingView = null;
- final RemoteViewsMetaData metaData = mCache.getMetaData();
- synchronized (metaData) {
- loadingView = metaData.createLoadingView(position, convertView, parent,
- mCache, mLayoutInflater, mRemoteViewsOnClickHandler);
- }
- return loadingView;
- } finally {
- if (hasNewItems) loadNextIndexInBackground();
- }
+ layout.onRemoteViewsLoaded(rv, mRemoteViewsOnClickHandler);
+ if (hasNewItems) loadNextIndexInBackground();
} else {
- // If the cache does not have the RemoteViews at this position, then create a
- // loading view and queue the actual position to be loaded in the background
- RemoteViewsFrameLayout loadingView = null;
- final RemoteViewsMetaData metaData = mCache.getMetaData();
- synchronized (metaData) {
- loadingView = metaData.createLoadingView(position, convertView, parent,
- mCache, mLayoutInflater, mRemoteViewsOnClickHandler);
- }
-
- mRequestedViews.add(position, loadingView);
+ // If the views is not loaded, apply the loading view. If the loading view doesn't
+ // exist, the layout will create a default view based on the firstView height.
+ layout.onRemoteViewsLoaded(mCache.getMetaData().mUserLoadingView,
+ mRemoteViewsOnClickHandler);
+ mRequestedViews.add(position, layout);
mCache.queueRequestedPositionToLoad(position);
loadNextIndexInBackground();
-
- return loadingView;
}
+ return layout;
}
}
@@ -1276,7 +1164,7 @@
// Re-request the new metadata (only after the notification to the factory)
updateTemporaryMetaData();
int newCount;
- ArrayList<Integer> visibleWindow;
+ int[] visibleWindow;
synchronized(mCache.getTemporaryMetaData()) {
newCount = mCache.getTemporaryMetaData().count;
visibleWindow = getVisibleWindow(mVisibleWindowLowerBound,
@@ -1311,26 +1199,33 @@
mNotifyDataSetChangedAfterOnServiceConnected = false;
}
- private ArrayList<Integer> getVisibleWindow(int lower, int upper, int count) {
- ArrayList<Integer> window = new ArrayList<Integer>();
-
+ /**
+ * Returns a sorted array of all integers between lower and upper.
+ */
+ private int[] getVisibleWindow(int lower, int upper, int count) {
// In the case that the window is invalid or uninitialized, return an empty window.
if ((lower == 0 && upper == 0) || lower < 0 || upper < 0) {
- return window;
+ return new int[0];
}
+ int[] window;
if (lower <= upper) {
- for (int i = lower; i <= upper; i++){
- window.add(i);
+ window = new int[upper + 1 - lower];
+ for (int i = lower, j = 0; i <= upper; i++, j++){
+ window[j] = i;
}
} else {
// If the upper bound is less than the lower bound it means that the visible window
// wraps around.
- for (int i = lower; i < count; i++) {
- window.add(i);
+ count = Math.max(count, lower);
+ window = new int[count - lower + upper + 1];
+ int j = 0;
+ // Add the entries in sorted order
+ for (int i = 0; i <= upper; i++, j++) {
+ window[j] = i;
}
- for (int i = 0; i <= upper; i++) {
- window.add(i);
+ for (int i = lower; i < count; i++, j++) {
+ window[j] = i;
}
}
return window;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ac77007..cd2c0d6 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "ThreadedRenderer"
#include <algorithm>
+#include <atomic>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
@@ -231,28 +232,13 @@
class NotifyHandler : public MessageHandler {
public:
- NotifyHandler(JavaVM* vm) : mVm(vm) {}
-
- void setObserver(ObserverProxy* observer) {
- mObserver = observer;
- }
-
- void setBuffer(BufferPool::Buffer* buffer) {
- mBuffer = buffer;
- }
-
- void setDropCount(int dropCount) {
- mDropCount = dropCount;
- }
+ NotifyHandler(JavaVM* vm, ObserverProxy* observer) : mVm(vm), mObserver(observer) {}
virtual void handleMessage(const Message& message);
private:
- JavaVM* mVm;
-
- sp<ObserverProxy> mObserver;
- BufferPool::Buffer* mBuffer = nullptr;
- int mDropCount = 0;
+ JavaVM* const mVm;
+ ObserverProxy* const mObserver;
};
static jlongArray get_metrics_buffer(JNIEnv* env, jobject observer) {
@@ -265,6 +251,9 @@
return reinterpret_cast<jlongArray>(buffer);
}
+/*
+ * Implements JNI layer for hwui frame metrics reporting.
+ */
class ObserverProxy : public FrameMetricsObserver {
public:
ObserverProxy(JavaVM *vm, jobject observer) : mVm(vm) {
@@ -284,7 +273,7 @@
mMessageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueLocal);
LOG_ALWAYS_FATAL_IF(mMessageQueue == nullptr, "message queue not available");
- mMessageHandler = new NotifyHandler(mVm);
+ mMessageHandler = new NotifyHandler(mVm, this);
LOG_ALWAYS_FATAL_IF(mMessageHandler == nullptr,
"OOM: unable to allocate NotifyHandler");
}
@@ -298,18 +287,53 @@
return mObserverWeak;
}
- virtual void notify(BufferPool::Buffer* buffer, int dropCount) {
- buffer->incRef();
- mMessageHandler->setBuffer(buffer);
- mMessageHandler->setObserver(this);
- mMessageHandler->setDropCount(dropCount);
- mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
+ bool getNextBuffer(JNIEnv* env, jlongArray sink, int* dropCount) {
+ FrameMetricsNotification& elem = mRingBuffer[mNextInQueue];
+
+ if (elem.hasData.load()) {
+ env->SetLongArrayRegion(sink, 0, kBufferSize, elem.buffer);
+ *dropCount = elem.dropCount;
+ mNextInQueue = (mNextInQueue + 1) % kRingSize;
+ elem.hasData = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void notify(const int64_t* stats) {
+ FrameMetricsNotification& elem = mRingBuffer[mNextFree];
+
+ if (!elem.hasData.load()) {
+ memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0]));
+
+ elem.dropCount = mDroppedReports;
+ mDroppedReports = 0;
+
+ incStrong(nullptr);
+ mNextFree = (mNextFree + 1) % kRingSize;
+ elem.hasData = true;
+
+ mMessageQueue->getLooper()->sendMessage(mMessageHandler, mMessage);
+ } else {
+ mDroppedReports++;
+ }
}
private:
static const int kBufferSize = static_cast<int>(FrameInfoIndex::NumIndexes);
+ static constexpr int kRingSize = 3;
- JavaVM* mVm;
+ class FrameMetricsNotification {
+ public:
+ FrameMetricsNotification() : hasData(false) {}
+
+ std::atomic_bool hasData;
+ int64_t buffer[kBufferSize];
+ int dropCount = 0;
+ };
+
+ JavaVM* const mVm;
jweak mObserverWeak;
jobject mJavaBufferGlobal;
@@ -317,28 +341,28 @@
sp<NotifyHandler> mMessageHandler;
Message mMessage;
+ int mNextFree = 0;
+ int mNextInQueue = 0;
+ FrameMetricsNotification mRingBuffer[kRingSize];
+
+ int mDroppedReports = 0;
};
void NotifyHandler::handleMessage(const Message& message) {
JNIEnv* env = getenv(mVm);
- ObserverProxy* observer = mObserver.get();
- LOG_ALWAYS_FATAL_IF(observer == nullptr, "received message with no observer configured");
- LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "received message with no data to report");
-
- jobject target = env->NewLocalRef(observer->getObserverReference());
+ jobject target = env->NewLocalRef(mObserver->getObserverReference());
if (target != nullptr) {
jlongArray javaBuffer = get_metrics_buffer(env, target);
- env->SetLongArrayRegion(javaBuffer,
- 0, mBuffer->getSize(), mBuffer->getBuffer());
- env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback,
- mDropCount);
+ int dropCount = 0;
+ while (mObserver->getNextBuffer(env, javaBuffer, &dropCount)) {
+ env->CallVoidMethod(target, gFrameMetricsObserverClassInfo.callback, dropCount);
+ }
env->DeleteLocalRef(target);
}
- mBuffer->release();
- mObserver.clear();
+ mObserver->decStrong(nullptr);
}
static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6a565033..6257122 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -232,7 +232,6 @@
LOCAL_SRC_FILES += \
$(hwui_test_common_src_files) \
- tests/unit/BufferPoolTests.cpp \
tests/unit/CanvasStateTests.cpp \
tests/unit/ClipAreaTests.cpp \
tests/unit/CrashHandlerInjector.cpp \
diff --git a/libs/hwui/BufferPool.h b/libs/hwui/BufferPool.h
deleted file mode 100644
index 005b399..0000000
--- a/libs/hwui/BufferPool.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "utils/RefBase.h"
-#include "utils/Log.h"
-#include "utils/Macros.h"
-
-#include <atomic>
-#include <stdint.h>
-#include <memory>
-#include <mutex>
-
-namespace android {
-namespace uirenderer {
-
-/*
- * Simple thread-safe pool of int64_t arrays of a provided size.
- *
- * Permits allocating a client-provided max number of buffers.
- * If all buffers are in use, refuses to service any more
- * acquire requests until buffers are re-released to the pool.
- */
-class BufferPool : public VirtualLightRefBase {
-public:
- class Buffer {
- PREVENT_COPY_AND_ASSIGN(Buffer);
- public:
- int64_t* getBuffer() { return mBuffer.get(); }
- size_t getSize() { return mSize; }
-
- void release() {
- LOG_ALWAYS_FATAL_IF(mPool.get() == nullptr, "attempt to release unacquired buffer");
- mPool->release(this);
- }
-
- Buffer* incRef() {
- mRefs++;
- return this;
- }
-
- int decRef() {
- int refs = mRefs.fetch_sub(1);
- LOG_ALWAYS_FATAL_IF(refs == 0, "buffer reference decremented below 0");
- return refs - 1;
- }
-
- bool isUniqueRef() {
- return mRefs.load() == 1;
- }
-
- private:
- friend class BufferPool;
-
- Buffer(BufferPool* pool, size_t size) : mRefs(1) {
- mSize = size;
- mBuffer.reset(new int64_t[size]);
- mPool = pool;
- }
-
- void setPool(BufferPool* pool) {
- mPool = pool;
- }
-
- std::unique_ptr<Buffer> mNext;
- std::unique_ptr<int64_t[]> mBuffer;
- sp<BufferPool> mPool;
- size_t mSize;
-
- std::atomic_int mRefs;
- };
-
- BufferPool(size_t bufferSize, size_t count)
- : mBufferSize(bufferSize), mCount(count) {}
-
- /**
- * Acquires a buffer from the buffer pool if available.
- *
- * Only `mCount` buffers are allowed to be in use at a single
- * instance.
- *
- * If no buffer is available, i.e. `mCount` buffers are in use,
- * returns nullptr.
- *
- * The pointer returned from this method *MUST NOT* be freed, instead
- * BufferPool::release() must be called upon it when the client
- * is done with it. Failing to release buffers will eventually make the
- * BufferPool refuse to service any more BufferPool::acquire() requests.
- */
- BufferPool::Buffer* acquire() {
- std::lock_guard<std::mutex> lock(mLock);
-
- if (mHead.get() != nullptr) {
- BufferPool::Buffer* res = mHead.release();
- mHead = std::move(res->mNext);
- res->mNext.reset(nullptr);
- res->setPool(this);
- res->incRef();
- return res;
- }
-
- if (mAllocatedCount < mCount) {
- ++mAllocatedCount;
- return new BufferPool::Buffer(this, mBufferSize);
- }
-
- return nullptr;
- }
-
- /**
- * Releases a buffer previously acquired by BufferPool::acquire().
- *
- * The released buffer is not valid after calling this method and
- * attempting to use will result in undefined behavior.
- */
- void release(BufferPool::Buffer* buffer) {
- std::lock_guard<std::mutex> lock(mLock);
-
- if (buffer->decRef() != 0) {
- return;
- }
-
- buffer->setPool(nullptr);
-
- BufferPool::Buffer* list = mHead.get();
- if (list == nullptr) {
- mHead.reset(buffer);
- mHead->mNext.reset(nullptr);
- return;
- }
-
- while (list->mNext.get() != nullptr) {
- list = list->mNext.get();
- }
-
- list->mNext.reset(buffer);
- }
-
- /*
- * Used for testing.
- */
- size_t getAvailableBufferCount() {
- size_t remainingToAllocateCount = mCount - mAllocatedCount;
-
- BufferPool::Buffer* list = mHead.get();
- if (list == nullptr) return remainingToAllocateCount;
-
- int count = 1;
- while (list->mNext.get() != nullptr) {
- count++;
- list = list->mNext.get();
- }
-
- return count + remainingToAllocateCount;
- }
-
-private:
- mutable std::mutex mLock;
-
- size_t mBufferSize;
- size_t mCount;
- size_t mAllocatedCount = 0;
- std::unique_ptr<BufferPool::Buffer> mHead;
-};
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 2b42a80..4f81c86 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -18,14 +18,12 @@
#include <utils/RefBase.h>
-#include "BufferPool.h"
-
namespace android {
namespace uirenderer {
class FrameMetricsObserver : public VirtualLightRefBase {
public:
- virtual void notify(BufferPool::Buffer* buffer, int dropCount);
+ virtual void notify(const int64_t* buffer);
};
}; // namespace uirenderer
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
index 0831d24..c1cd0a92 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -19,7 +19,6 @@
#include <utils/RefBase.h>
#include <utils/Log.h>
-#include "BufferPool.h"
#include "FrameInfo.h"
#include "FrameMetricsObserver.h"
@@ -31,10 +30,7 @@
class FrameMetricsReporter {
public:
- FrameMetricsReporter() {
- mBufferPool = new BufferPool(kBufferSize, kBufferCount);
- LOG_ALWAYS_FATAL_IF(mBufferPool.get() == nullptr, "OOM: unable to allocate buffer pool");
- }
+ FrameMetricsReporter() {}
void addObserver(FrameMetricsObserver* observer) {
mObservers.push_back(observer);
@@ -55,36 +51,13 @@
}
void reportFrameMetrics(const int64_t* stats) {
- BufferPool::Buffer* statsBuffer = mBufferPool->acquire();
-
- if (statsBuffer != nullptr) {
- // copy in frame stats
- memcpy(statsBuffer->getBuffer(), stats, kBufferSize * sizeof(*stats));
-
- // notify on requested threads
- for (size_t i = 0; i < mObservers.size(); i++) {
- mObservers[i]->notify(statsBuffer, mDroppedReports);
- }
-
- // drop our reference
- statsBuffer->release();
- mDroppedReports = 0;
- } else {
- mDroppedReports++;
+ for (size_t i = 0; i < mObservers.size(); i++) {
+ mObservers[i]->notify(stats);
}
}
- int getDroppedReports() { return mDroppedReports; }
-
private:
- static const size_t kBufferCount = 3;
- static const size_t kBufferSize = static_cast<size_t>(FrameInfoIndex::NumIndexes);
-
std::vector< sp<FrameMetricsObserver> > mObservers;
-
- sp<BufferPool> mBufferPool;
-
- int mDroppedReports = 0;
};
}; // namespace uirenderer
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 1f81970..cb61e51 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -159,14 +159,6 @@
}
}
- long getDroppedFrameReportCount() {
- if (mFrameMetricsReporter.get() != nullptr) {
- return mFrameMetricsReporter->getDroppedReports();
- }
-
- return 0;
- }
-
private:
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
diff --git a/libs/hwui/tests/unit/BufferPoolTests.cpp b/libs/hwui/tests/unit/BufferPoolTests.cpp
deleted file mode 100644
index 44e6d3a..0000000
--- a/libs/hwui/tests/unit/BufferPoolTests.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include <BufferPool.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace uirenderer {
-
-TEST(BufferPool, acquireThenRelease) {
- static const int numRuns = 5;
-
- // 10 buffers of size 1
- static const size_t bufferSize = 1;
- static const size_t bufferCount = 10;
- sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
-
- for (int run = 0; run < numRuns; run++) {
- BufferPool::Buffer* acquiredBuffers[bufferCount];
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- ASSERT_NE(nullptr, acquiredBuffers[i]);
- ASSERT_TRUE(acquiredBuffers[i]->isUniqueRef());
- }
-
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
- }
-}
-
-TEST(BufferPool, acquireReleaseInterleaved) {
- static const int numRuns = 5;
-
- // 10 buffers of size 1
- static const size_t bufferSize = 1;
- static const size_t bufferCount = 10;
-
- sp<BufferPool> pool = new BufferPool(bufferSize, bufferCount);
-
- for (int run = 0; run < numRuns; run++) {
- BufferPool::Buffer* acquiredBuffers[bufferCount];
-
- // acquire all
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- ASSERT_NE(nullptr, acquiredBuffers[i]);
- }
-
- // release half
- for (size_t i = 0; i < bufferCount / 2; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- const size_t expectedRemaining = bufferCount / 2;
- ASSERT_EQ(expectedRemaining, pool->getAvailableBufferCount());
-
- // acquire half
- for (size_t i = 0; i < bufferCount / 2; i++) {
- ASSERT_EQ(expectedRemaining - i, pool->getAvailableBufferCount());
- acquiredBuffers[i] = pool->acquire();
- }
-
- // acquire one more, should fail
- ASSERT_EQ(nullptr, pool->acquire());
-
- // release all
- for (size_t i = 0; i < bufferCount; i++) {
- ASSERT_EQ(i, pool->getAvailableBufferCount());
- acquiredBuffers[i]->release();
- acquiredBuffers[i] = nullptr;
- }
-
- ASSERT_EQ(bufferCount, pool->getAvailableBufferCount());
- }
-}
-
-};
-};
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 16e1c5c..da4a038 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1940,6 +1940,15 @@
* </ul>
*/
public void onHardwareVideoUnavailable(int reason) { }
+
+ @Override
+ void release() {
+ if (mHardwareSession != null) {
+ mHardwareSession.release();
+ mHardwareSession = null;
+ }
+ super.release();
+ }
}
/** @hide */
diff --git a/packages/DocumentsUI/res/drawable/ic_root_home.xml b/packages/DocumentsUI/res/drawable/ic_root_documents.xml
similarity index 86%
rename from packages/DocumentsUI/res/drawable/ic_root_home.xml
rename to packages/DocumentsUI/res/drawable/ic_root_documents.xml
index 696ee05..afd886d 100644
--- a/packages/DocumentsUI/res/drawable/ic_root_home.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_documents.xml
@@ -20,5 +20,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
- android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
+ android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/>
</vector>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 470989d..648c79e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -23,7 +23,6 @@
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
import android.app.Activity;
import android.app.Fragment;
@@ -464,8 +463,7 @@
* Set mode based on explicit user action.
*/
void setViewMode(@ViewMode int mode) {
- checkState(mState.stack.root != null);
- LocalPreferences.setViewMode(this, mState.stack.root, mode);
+ LocalPreferences.setViewMode(this, getCurrentRoot(), mode);
mState.derivedMode = mode;
// view icon needs to be updated, but we *could* do it
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 4233b36..0ae2a5c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -536,7 +536,11 @@
@Override
public void onItemStateChanged(String modelId, boolean selected) {
final Cursor cursor = mModel.getItem(modelId);
- checkNotNull(cursor, "Cursor cannot be null.");
+ if (cursor == null) {
+ Log.e(TAG, "Model returned null cursor for document: " + modelId
+ + ". Ignoring state changed event.");
+ return;
+ }
// TODO: Should this be happening in onSelectionChanged? Technically this callback is
// triggered on "silent" selection updates (i.e. we might be reacting to unfinalized
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 4b5499a..1c696ad 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -39,6 +39,7 @@
import java.io.IOException;
import java.net.ProtocolException;
import java.text.Collator;
+import java.util.Objects;
/**
* Representation of a {@link Document}.
@@ -263,16 +264,23 @@
return derivedUri.hashCode() + mimeType.hashCode();
}
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (!(other instanceof DocumentInfo)) {
+ public boolean equals(Object o) {
+ if (o == null) {
return false;
}
- DocumentInfo that = (DocumentInfo) other;
- // Uri + mime type should be totally unique.
- return derivedUri.equals(that.derivedUri) && mimeType.equals(that.mimeType);
+ if (this == o) {
+ return true;
+ }
+
+ if (o instanceof DocumentInfo) {
+ DocumentInfo other = (DocumentInfo) o;
+ // Uri + mime type should be totally unique.
+ return Objects.equals(derivedUri, other.derivedUri)
+ && Objects.equals(mimeType, other.mimeType);
+ }
+
+ return false;
}
public static String getCursorString(Cursor cursor, String columnName) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 3f14a55..f4a97be 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -171,7 +171,7 @@
// TODO: remove these special case icons
if (isHome()) {
- derivedIcon = R.drawable.ic_root_home;
+ derivedIcon = R.drawable.ic_root_documents;
derivedType = TYPE_LOCAL;
} else if (isExternalStorage()) {
derivedIcon = R.drawable.ic_root_smartphone;
@@ -276,12 +276,21 @@
@Override
public boolean equals(Object o) {
- if (o instanceof RootInfo) {
- final RootInfo root = (RootInfo) o;
- return Objects.equals(authority, root.authority) && Objects.equals(rootId, root.rootId);
- } else {
+ if (o == null) {
return false;
}
+
+ if (this == o) {
+ return true;
+ }
+
+ if (o instanceof RootInfo) {
+ RootInfo other = (RootInfo) o;
+ return Objects.equals(authority, other.authority)
+ && Objects.equals(rootId, other.rootId);
+ }
+
+ return false;
}
@Override
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
index b74b985..f057850 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java
@@ -23,18 +23,44 @@
@SmallTest
public class StateTest extends AndroidTestCase {
- public void testPushDocument() {
- final State state = new State();
- final DocumentInfo infoFirst = new DocumentInfo();
- infoFirst.displayName = "firstDirectory";
- final DocumentInfo infoSecond = new DocumentInfo();
- infoSecond.displayName = "secondDirectory";
- assertFalse(state.hasLocationChanged());
- state.pushDocument(infoFirst);
- state.pushDocument(infoSecond);
- assertTrue(state.hasLocationChanged());
- assertEquals("secondDirectory", state.stack.getFirst().displayName);
- state.popDocument();
- assertEquals("firstDirectory", state.stack.getFirst().displayName);
+
+ private static final DocumentInfo DIR_1;
+ private static final DocumentInfo DIR_2;
+
+ private State mState;
+
+ static {
+ DIR_1 = new DocumentInfo();
+ DIR_1.displayName = "firstDirectory";
+ DIR_2 = new DocumentInfo();
+ DIR_2.displayName = "secondDirectory";
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mState = new State();
+ }
+
+ public void testInitialStateEmpty() {
+ assertFalse(mState.hasLocationChanged());
+ }
+
+ public void testPushDocument_ChangesLocation() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ assertTrue(mState.hasLocationChanged());
+ }
+
+ public void testPushDocument_ModifiesStack() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ assertEquals(DIR_2, mState.stack.getFirst());
+ }
+
+ public void testPopDocument_ModifiesStack() {
+ mState.pushDocument(DIR_1);
+ mState.pushDocument(DIR_2);
+ mState.popDocument();
+ assertEquals(DIR_1, mState.stack.getFirst());
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
index a6aba7b..2481dc3 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/model/DocumentInfoTest.java
@@ -22,30 +22,36 @@
@SmallTest
public class DocumentInfoTest extends AndroidTestCase {
+ private static final DocumentInfo TEST_DOC
+ = createDocInfo("authority.a", "doc.1", "text/plain");
+
public void testEquals() throws Exception {
- DocumentInfo doc = createDocInfo("authority.a", "doc.1", "text/plain");
- assertEquals(doc, doc);
+ assertEquals(TEST_DOC, TEST_DOC);
+ assertEquals(TEST_DOC, createDocInfo("authority.a", "doc.1", "text/plain"));
+ }
+
+ public void testEquals_HandlesNulls() throws Exception {
+ assertFalse(TEST_DOC.equals(null));
+ }
+
+ public void testEquals_HandlesNullFields() throws Exception {
+ assertFalse(TEST_DOC.equals(new DocumentInfo()));
+ assertFalse(new DocumentInfo().equals(TEST_DOC));
}
public void testNotEquals_differentAuthority() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.b", "doc.1", "text/plain");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.b", "doc.1", "text/plain")));
}
public void testNotEquals_differentDocId() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.a", "doc.2", "text/plain");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.a", "doc.2", "text/plain")));
}
public void testNotEquals_differentMimetype() throws Exception {
- DocumentInfo docA = createDocInfo("authority.a", "doc.1", "text/plain");
- DocumentInfo docB = createDocInfo("authority.a", "doc.1", "image/png");
- assertFalse(docA.equals(docB));
+ assertFalse(TEST_DOC.equals(createDocInfo("authority.a", "doc.1", "image/png")));
}
- private DocumentInfo createDocInfo(String authority, String docId, String mimeType) {
+ private static DocumentInfo createDocInfo(String authority, String docId, String mimeType) {
DocumentInfo doc = new DocumentInfo();
doc.authority = authority;
doc.documentId = docId;
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
index e48436e..8b16d3c 100644
--- a/packages/ExternalStorageProvider/res/values/strings.xml
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -20,6 +20,6 @@
<!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
<string name="root_internal_storage">Internal storage</string>
- <!-- Title for user home dir. [CHAR LIMIT=24] -->
- <string name="root_home">Home</string>
+ <!-- Title for directory in which a user may store their own documents and files. [CHAR LIMIT=24] -->
+ <string name="root_documents">Documents</string>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index f89934d..97dfd47 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -199,7 +199,7 @@
final RootInfo root = new RootInfo();
root.rootId = ROOT_ID_HOME;
mRoots.put(root.rootId, root);
- root.title = getContext().getString(R.string.root_home);
+ root.title = getContext().getString(R.string.root_documents);
// Only report bytes on *volumes*...as a matter of policy.
root.reportAvailableBytes = false;
@@ -214,9 +214,9 @@
// Create the "Home" directory on disk, but don't the localized root.title
// since the directories shouldn't be localized.
root.visiblePath = new File(
- primaryVolume.getPathForUser(userId), Environment.DIRECTORY_HOME);
+ primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
root.path = new File(
- primaryVolume.getInternalPathForUser(userId), root.rootId);
+ primaryVolume.getInternalPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
try {
root.docId = getDocIdForFile(root.path);
} catch (FileNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
index 43a1be1..9238928 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
@@ -40,4 +40,15 @@
public static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9;
/** The user tapped on the status bar to open quick settings, from shade. */
public static final int SYSUI_TAP_TO_OPEN_QS = 10;
+
+ /** Secondary user tries binding to the system sysui service */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE = 1;
+ /** Secondary user is bound to the system sysui service */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND = 2;
+ /** Secondary user loses connection after system sysui has died */
+ public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND = 3;
+ /** System sysui registers secondary user's callbacks */
+ public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER = 4;
+ /** System sysui unregisters secondary user's callbacks (after death) */
+ public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER = 5;
}
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index a584cf6..1601675 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -51,3 +51,13 @@
# SearchPanelView.java
# ---------------------------
36050 sysui_searchpanel_touch (type|1),(x|1),(y|1)
+
+# ---------------------------
+# Recents.java, RecentsSystemUser.java
+# ---------------------------
+## type: 1: USER_BIND_SERVICE Secondary user tries binding to the system sysui service
+## 2: USER_SYSTEM_BOUND Secondary user is bound to the system sysui service
+## 3: USER_SYSTEM_UNBOUND Secondary user loses connection after system sysui has died
+## 4: SYSTEM_REGISTER_USER System sysui registers user's callbacks
+## 5: SYSTEM_UNREGISTER_USER System sysui unregisters user's callbacks (after death)
+36060 sysui_recents_connection (type|1),(user|1)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e4fd31d..f5ae351 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -31,10 +31,13 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.EventLog;
import android.util.Log;
import android.view.Display;
import android.view.View;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
@@ -83,20 +86,23 @@
private int mDraggingInRecentsCurrentUser;
// Only For system user, this is the callbacks instance we return to each secondary user
- private RecentsSystemUser mSystemUserCallbacks;
+ private RecentsSystemUser mSystemToUserCallbacks;
// Only for secondary users, this is the callbacks instance provided by the system user to make
// calls back
- private IRecentsSystemUserCallbacks mCallbacksToSystemUser;
+ private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
// The set of runnables to run after binding to the system user's service.
private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
// Only for secondary users, this is the death handler for the binder from the system user
- private final IBinder.DeathRecipient mCallbacksToSystemUserDeathRcpt = new IBinder.DeathRecipient() {
+ private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- mCallbacksToSystemUser = null;
+ mUserToSystemCallbacks = null;
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
+ sSystemServicesProxy.getProcessUser());
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
@@ -109,16 +115,19 @@
};
// Only for secondary users, this is the service connection we use to connect to the system user
- private final ServiceConnection mServiceConnectionToSystemUser = new ServiceConnection() {
+ private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
- mCallbacksToSystemUser = IRecentsSystemUserCallbacks.Stub.asInterface(
+ mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
service);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
+ sSystemServicesProxy.getProcessUser());
// Listen for system user's death, so that we can reconnect later
try {
- service.linkToDeath(mCallbacksToSystemUserDeathRcpt, 0);
+ service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
} catch (RemoteException e) {
Log.e(TAG, "Lost connection to (System) SystemUI", e);
}
@@ -142,7 +151,7 @@
* Returns the callbacks interface that non-system users can call.
*/
public IBinder getSystemUserCallbacks() {
- return mSystemUserCallbacks;
+ return mSystemToUserCallbacks;
}
public static RecentsTaskLoader getTaskLoader() {
@@ -190,7 +199,7 @@
if (sSystemServicesProxy.isSystemUser(processUser)) {
// For the system user, initialize an instance of the interface that we can pass to the
// secondary user
- mSystemUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+ mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
} else {
// For the secondary user, bind to the primary user's service to get a persistent
// interface to register its implementation and to later update its state
@@ -224,9 +233,9 @@
mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
true /* animate */, false /* reloadTasks */);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
@@ -260,9 +269,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -295,9 +304,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.toggleRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.toggleRecents();
@@ -326,9 +335,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.preloadRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.preloadRecents();
@@ -354,9 +363,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.cancelPreloadingRecents();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.cancelPreloadingRecents();
@@ -387,9 +396,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
@@ -413,9 +422,9 @@
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecents(distanceFromTop);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
@@ -436,9 +445,9 @@
if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
mImpl.onDraggingInRecentsEnded(velocity);
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
mDraggingInRecentsCurrentUser);
if (callbacks != null) {
try {
@@ -484,9 +493,9 @@
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.onConfigurationChanged();
} else {
- if (mSystemUserCallbacks != null) {
+ if (mSystemToUserCallbacks != null) {
IRecentsNonSystemUserCallbacks callbacks =
- mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
if (callbacks != null) {
try {
callbacks.onConfigurationChanged();
@@ -512,7 +521,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.updateRecentsVisibility(event.visible);
+ mUserToSystemCallbacks.updateRecentsVisibility(event.visible);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -533,7 +542,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.startScreenPinning();
+ mUserToSystemCallbacks.startScreenPinning();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -549,7 +558,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendRecentsDrawnEvent();
+ mUserToSystemCallbacks.sendRecentsDrawnEvent();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -565,7 +574,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+ mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -581,7 +590,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.sendLaunchRecentsEvent();
+ mUserToSystemCallbacks.sendLaunchRecentsEvent();
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
@@ -599,7 +608,7 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+ mUserToSystemCallbacks.registerNonSystemUserCallbacks(
new RecentsImplProxy(mImpl), processUser);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register", e);
@@ -614,11 +623,14 @@
*/
private void postToSystemUser(final Runnable onConnectRunnable) {
mOnConnectRunnables.add(onConnectRunnable);
- if (mCallbacksToSystemUser == null) {
+ if (mUserToSystemCallbacks == null) {
Intent systemUserServiceIntent = new Intent();
systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
- mServiceConnectionToSystemUser, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+ mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
+ sSystemServicesProxy.getProcessUser());
if (!bound) {
// Retry after a fixed duration
mHandler.postDelayed(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9d4f425..c2a6108 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -230,7 +230,7 @@
* Dismisses the history view back into the stack view.
*/
boolean dismissHistory() {
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
return true;
}
@@ -447,7 +447,7 @@
// Reset some states
mIgnoreAltTabRelease = false;
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
}
@@ -503,13 +503,16 @@
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+ }
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
- if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
+ if (RecentsDebugFlags.Static.EnableHistory &&
+ savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
EventBus.getDefault().send(new ShowHistoryEvent());
}
}
@@ -603,7 +606,7 @@
/**** EventBus events ****/
public final void onBusEvent(ToggleRecentsEvent event) {
- if (!dismissHistory()) {
+ if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
if (launchState.launchedFromHome) {
dismissRecentsToHome(true /* animateTaskViews */);
@@ -614,7 +617,7 @@
}
public final void onBusEvent(IterateRecentsEvent event) {
- if (!dismissHistory()) {
+ if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
// Start dozing after the recents button is clicked
@@ -651,7 +654,7 @@
}
} else if (event.triggeredFromHomeKey) {
// Otherwise, dismiss Recents to Home
- if (mRecentsView.isHistoryVisible()) {
+ if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
// If the history view is visible, then just cross-fade home
ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
R.anim.recents_to_launcher_enter,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 711d834..cd64323 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -37,6 +37,8 @@
public static final boolean DisableBackgroundCache = false;
// Enables the task affiliations
public static final boolean EnableAffiliatedTaskGroups = true;
+ // Enables the history
+ public static final boolean EnableHistory = false;
// Overrides the Tuner flags and enables the fast toggle and timeout
public static final boolean EnableFastToggleTimeoutOverride = true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index e0efaa5..8de964b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -406,9 +406,9 @@
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
MutableBoolean topTaskHome = new MutableBoolean(true);
- RecentsTaskLoader loader = Recents.getTaskLoader();
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ sInstanceLoadPlan = loader.createLoadPlan(mContext);
sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
TaskStack stack = sInstanceLoadPlan.getTaskStack();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index ae0051c..f8000b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -19,9 +19,12 @@
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -46,7 +49,8 @@
}
@Override
- public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks, int userId) {
+ public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks,
+ final int userId) {
try {
final IRecentsNonSystemUserCallbacks callback =
IRecentsNonSystemUserCallbacks.Stub.asInterface(nonSystemUserCallbacks);
@@ -54,9 +58,14 @@
@Override
public void binderDied() {
mNonSystemUserRecents.removeAt(mNonSystemUserRecents.indexOfValue(callback));
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER,
+ userId);
}
}, 0);
mNonSystemUserRecents.put(userId, callback);
+ EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+ EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER, userId);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register NonSystemUserCallbacks", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c4db485..2e45627 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -143,21 +143,24 @@
final float cornerRadius = context.getResources().getDimensionPixelSize(
R.dimen.recents_task_view_rounded_corners_radius);
LayoutInflater inflater = LayoutInflater.from(context);
- mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
- mHistoryButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- EventBus.getDefault().send(new ToggleHistoryEvent());
- }
- });
- addView(mHistoryButton);
- mHistoryButton.setClipToOutline(true);
- mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
- }
- });
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this,
+ false);
+ mHistoryButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ EventBus.getDefault().send(new ToggleHistoryEvent());
+ }
+ });
+ addView(mHistoryButton);
+ mHistoryButton.setClipToOutline(true);
+ mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+ }
+ });
+ }
mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
addView(mEmptyView);
@@ -331,7 +334,9 @@
mTaskStackView.setVisibility(View.INVISIBLE);
mEmptyView.setVisibility(View.VISIBLE);
mEmptyView.bringToFront();
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton.bringToFront();
+ }
}
/**
@@ -347,7 +352,9 @@
if (mSearchBar != null) {
mSearchBar.bringToFront();
}
- mHistoryButton.bringToFront();
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ mHistoryButton.bringToFront();
+ }
}
@Override
@@ -397,21 +404,23 @@
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
- // Measure the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
- }
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Measure the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+ }
- // Measure the history button within the constraints of the space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- measureChild(mHistoryButton,
- MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- measureChild(mHistoryClearAllButton,
+ // Measure the history button within the constraints of the space above the stack
+ Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+ measureChild(mHistoryButton,
MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ measureChild(mHistoryClearAllButton,
+ MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+ }
}
setMeasuredDimension(width, height);
@@ -443,36 +452,39 @@
mEmptyView.layout(left, top, right, bottom);
}
- // Layout the history view
- if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
- mHistoryView.layout(left, top, right, bottom);
- }
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Layout the history view
+ if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+ mHistoryView.layout(left, top, right, bottom);
+ }
- // Layout the history button such that its drawable is start-aligned with the stack,
- // vertically centered in the available space above the stack
- Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
- int historyLeft = isLayoutRtl()
- ? historyButtonRect.right + mHistoryButton.getPaddingStart()
- - mHistoryButton.getMeasuredWidth()
- : historyButtonRect.left - mHistoryButton.getPaddingStart();
- int historyTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
- mHistoryButton.layout(historyLeft, historyTop,
- historyLeft + mHistoryButton.getMeasuredWidth(),
- historyTop + mHistoryButton.getMeasuredHeight());
+ // Layout the history button such that its drawable is start-aligned with the stack,
+ // vertically centered in the available space above the stack
+ Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+ int historyLeft = isLayoutRtl()
+ ? historyButtonRect.right + mHistoryButton.getPaddingStart()
+ - mHistoryButton.getMeasuredWidth()
+ : historyButtonRect.left - mHistoryButton.getPaddingStart();
+ int historyTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
+ mHistoryButton.layout(historyLeft, historyTop,
+ historyLeft + mHistoryButton.getMeasuredWidth(),
+ historyTop + mHistoryButton.getMeasuredHeight());
- // Layout the history clear all button such that it is end-aligned with the stack,
- // vertically centered in the available space above the stack
- if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
- int clearAllLeft = isLayoutRtl()
- ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
- : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
- - mHistoryClearAllButton.getMeasuredWidth();
- int clearAllTop = historyButtonRect.top +
- (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) / 2;
- mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
- clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
- clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+ // Layout the history clear all button such that it is end-aligned with the stack,
+ // vertically centered in the available space above the stack
+ if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+ int clearAllLeft = isLayoutRtl()
+ ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
+ : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
+ - mHistoryClearAllButton.getMeasuredWidth();
+ int clearAllTop = historyButtonRect.top +
+ (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) /
+ 2;
+ mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
+ clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
+ clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+ }
}
if (mAwaitingFirstLayout) {
@@ -540,9 +552,11 @@
}
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
- // Hide the history button
int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
- hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ // Hide the history button
+ hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+ }
animateBackgroundScrim(0f, taskViewExitToHomeDuration);
}
@@ -675,11 +689,17 @@
// Reset the view state
mAwaitingFirstLayout = true;
mLastTaskLaunchedWasFreeform = false;
- hideHistoryButton(0, false /* translate */);
+ if (RecentsDebugFlags.Static.EnableHistory) {
+ hideHistoryButton(0, false /* translate */);
+ }
}
}
public final void onBusEvent(ToggleHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryView != null && mHistoryView.isVisible()) {
EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
} else {
@@ -688,6 +708,10 @@
}
public final void onBusEvent(ShowHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
@@ -746,6 +770,10 @@
}
public final void onBusEvent(HideHistoryEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
// Animate the empty view in parallel with the history view (the task view animations are
// handled in TaskStackView)
Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
@@ -765,10 +793,18 @@
}
public final void onBusEvent(ShowHistoryButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
showHistoryButton(150, event.translate);
}
public final void onBusEvent(HideHistoryButtonEvent event) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
hideHistoryButton(100, true /* translate */);
}
@@ -776,6 +812,10 @@
* Shows the history button.
*/
private void showHistoryButton(final int duration, final boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
if (mHistoryButton.getVisibility() == View.INVISIBLE) {
mHistoryButton.setVisibility(View.VISIBLE);
@@ -808,6 +848,10 @@
* Hides the history button.
*/
private void hideHistoryButton(int duration, boolean translate) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
hideHistoryButton(duration, translate, postAnimationTrigger);
postAnimationTrigger.flushLastDecrementRunnables();
@@ -818,6 +862,10 @@
*/
private void hideHistoryButton(int duration, boolean translate,
final ReferenceCountedTrigger postAnimationTrigger) {
+ if (!RecentsDebugFlags.Static.EnableHistory) {
+ return;
+ }
+
if (mHistoryButton.getVisibility() == View.VISIBLE) {
if (translate) {
mHistoryButton.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 890b445..2cd0c19 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -467,12 +467,13 @@
// Setup the end listener to return all the hidden views to the view pool after the
// focus animation
- AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+ ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
+ postAnimTrigger.addLastDecrementRunnable(new Runnable() {
@Override
- public void onAnimationEnd(Animator animation) {
+ public void run() {
mStackView.bindVisibleTaskViews(newScroll);
}
- };
+ });
List<TaskView> taskViews = mStackView.getTaskViews();
int taskViewCount = taskViews.size();
@@ -513,7 +514,8 @@
AnimationProps anim = new AnimationProps()
.setDuration(AnimationProps.BOUNDS, duration)
.setInterpolator(AnimationProps.BOUNDS, interpolator)
- .setListener(endListener);
+ .setListener(postAnimTrigger.decrementOnAnimationEnd());
+ postAnimTrigger.increment();
mStackView.updateTaskViewToTransform(tv, toTransform, anim);
}
return willScroll;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 79c21f3..33315c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -107,7 +107,7 @@
mPanel.setPanelScrimMinFraction((float) expandedHeight
/ mPanel.getMaxPanelHeight());
mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
- mPanel.clearNotificattonEffects();
+ mPanel.clearNotificationEffects();
return true;
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 88a7843..1a0acbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -89,13 +89,13 @@
private KeyguardAffordanceHelper mAfforanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
- private QSContainer mQsContainer;
+ protected QSContainer mQsContainer;
private KeyguardStatusView mKeyguardStatusView;
private TextView mClockView;
private View mReserveNotificationSpace;
private View mQsNavbarScrim;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private NotificationStackScrollLayout mNotificationStackScroller;
+ protected NotificationStackScrollLayout mNotificationStackScroller;
private boolean mAnimateNextTopPaddingChange;
private int mTrackingPointer;
@@ -126,9 +126,9 @@
private float mInitialTouchY;
private float mLastTouchX;
private float mLastTouchY;
- private float mQsExpansionHeight;
- private int mQsMinExpansionHeight;
- private int mQsMaxExpansionHeight;
+ protected float mQsExpansionHeight;
+ protected int mQsMinExpansionHeight;
+ protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
@@ -1072,8 +1072,8 @@
private void setKeyguardBottomAreaVisibility(int statusBarState,
boolean goingToFullShade) {
+ mKeyguardBottomArea.animate().cancel();
if (goingToFullShade) {
- mKeyguardBottomArea.animate().cancel();
mKeyguardBottomArea.animate()
.alpha(0f)
.setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
@@ -1083,13 +1083,11 @@
.start();
} else if (statusBarState == StatusBarState.KEYGUARD
|| statusBarState == StatusBarState.SHADE_LOCKED) {
- mKeyguardBottomArea.animate().cancel();
if (!mDozing) {
mKeyguardBottomArea.setVisibility(View.VISIBLE);
}
mKeyguardBottomArea.setAlpha(1f);
} else {
- mKeyguardBottomArea.animate().cancel();
mKeyguardBottomArea.setVisibility(View.GONE);
mKeyguardBottomArea.setAlpha(1f);
}
@@ -1196,7 +1194,7 @@
}
}
- private void updateQsExpansion() {
+ protected void updateQsExpansion() {
mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
}
@@ -1238,7 +1236,7 @@
}
}
- private void requestScrollerTopPaddingUpdate(boolean animate) {
+ protected void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
mAnimateNextTopPaddingChange || animate,
mKeyguardShowing
@@ -1520,16 +1518,12 @@
updateQsExpansion();
}
- private float getHeaderTranslation() {
+ protected float getHeaderTranslation() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
return 0;
}
if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
- if (mExpandedHeight / HEADER_RUBBERBAND_FACTOR >= mQsMinExpansionHeight) {
- return 0;
- } else {
- return mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight;
- }
+ return Math.min(0, mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight);
}
float stackTranslation = mNotificationStackScroller.getStackTranslation();
float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
@@ -2191,7 +2185,7 @@
*
* @param x the x-coordinate the touch event
*/
- private void updateVerticalPanelPosition(float x) {
+ protected void updateVerticalPanelPosition(float x) {
if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
resetVerticalPanelPosition();
return;
@@ -2216,7 +2210,7 @@
mQsContainer.setTranslationX(translation);
}
- private void updateStackHeight(float stackHeight) {
+ protected void updateStackHeight(float stackHeight) {
mNotificationStackScroller.setStackHeight(stackHeight);
updateKeyguardBottomAreaAlpha();
}
@@ -2225,7 +2219,7 @@
mBar.panelScrimMinFractionChanged(minFraction);
}
- public void clearNotificattonEffects() {
+ public void clearNotificationEffects() {
mStatusBar.clearNotificationEffects();
}
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3dff37b..3bef19e 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2346,62 +2346,75 @@
ALOGD("nScriptGroupCreate, con(%p)", (RsContext)con);
}
+ jlong id = 0;
+
+ RsScriptKernelID* kernelsPtr;
jint kernelsLen = _env->GetArrayLength(_kernels);
jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
+
+ RsScriptKernelID* srcPtr;
+ jint srcLen = _env->GetArrayLength(_src);
+ jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
+
+ RsScriptKernelID* dstkPtr;
+ jint dstkLen = _env->GetArrayLength(_dstk);
+ jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
+
+ RsScriptKernelID* dstfPtr;
+ jint dstfLen = _env->GetArrayLength(_dstf);
+ jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
+
+ RsType* typesPtr;
+ jint typesLen = _env->GetArrayLength(_types);
+ jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
+
if (jKernelsPtr == nullptr) {
ALOGE("Failed to get Java array elements: kernels");
- return 0;
+ goto cleanup;
}
- RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
+ if (jSrcPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: src");
+ goto cleanup;
+ }
+ if (jDstkPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: dstk");
+ goto cleanup;
+ }
+ if (jDstfPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: dstf");
+ goto cleanup;
+ }
+ if (jTypesPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: types");
+ goto cleanup;
+ }
+
+ kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
for(int i = 0; i < kernelsLen; ++i) {
kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
}
- jint srcLen = _env->GetArrayLength(_src);
- jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
- if (jSrcPtr == nullptr) {
- ALOGE("Failed to get Java array elements: src");
- return 0;
- }
- RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
+ srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
for(int i = 0; i < srcLen; ++i) {
srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
}
- jint dstkLen = _env->GetArrayLength(_dstk);
- jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
- if (jDstkPtr == nullptr) {
- ALOGE("Failed to get Java array elements: dstk");
- return 0;
- }
- RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
+ dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
for(int i = 0; i < dstkLen; ++i) {
dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
}
- jint dstfLen = _env->GetArrayLength(_dstf);
- jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
- if (jDstfPtr == nullptr) {
- ALOGE("Failed to get Java array elements: dstf");
- return 0;
- }
- RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
+ dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
for(int i = 0; i < dstfLen; ++i) {
dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
}
- jint typesLen = _env->GetArrayLength(_types);
- jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
- if (jTypesPtr == nullptr) {
- ALOGE("Failed to get Java array elements: types");
- return 0;
- }
- RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
+ typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
for(int i = 0; i < typesLen; ++i) {
typesPtr[i] = (RsType)jTypesPtr[i];
}
- jlong id = (jlong)(uintptr_t)rsScriptGroupCreate((RsContext)con,
+ id = (jlong)(uintptr_t)rsScriptGroupCreate((RsContext)con,
(RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
(RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
(RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
@@ -2413,11 +2426,24 @@
free(dstkPtr);
free(dstfPtr);
free(typesPtr);
- _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
- _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
- _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
- _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
- _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
+
+cleanup:
+ if (jKernelsPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
+ }
+ if (jSrcPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
+ }
+ if (jDstkPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
+ }
+ if (jDstfPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
+ }
+ if (jTypesPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
+ }
+
return id;
}
@@ -2662,45 +2688,61 @@
ALOGD("nMeshCreate, con(%p)", (RsContext)con);
}
+ jlong id = 0;
+
+ RsAllocation* vtxPtr;
jint vtxLen = _env->GetArrayLength(_vtx);
jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, nullptr);
+
+ RsAllocation* idxPtr;
+ jint idxLen = _env->GetArrayLength(_idx);
+ jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
+
+ jint primLen = _env->GetArrayLength(_prim);
+ jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
+
if (jVtxPtr == nullptr) {
ALOGE("Failed to get Java array elements: vtx");
- return 0;
+ goto cleanupMesh;
}
- RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
+ if (jIdxPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: idx");
+ goto cleanupMesh;
+ }
+ if (primPtr == nullptr) {
+ ALOGE("Failed to get Java array elements: prim");
+ goto cleanupMesh;
+ }
+
+ vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
for(int i = 0; i < vtxLen; ++i) {
vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
}
- jint idxLen = _env->GetArrayLength(_idx);
- jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
- if (jIdxPtr == nullptr) {
- ALOGE("Failed to get Java array elements: idx");
- return 0;
- }
- RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
+ idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
for(int i = 0; i < idxLen; ++i) {
idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
}
- jint primLen = _env->GetArrayLength(_prim);
- jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
- if (primPtr == nullptr) {
- ALOGE("Failed to get Java array elements: prim");
- return 0;
- }
-
- jlong id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
- (RsAllocation *)vtxPtr, vtxLen,
- (RsAllocation *)idxPtr, idxLen,
- (uint32_t *)primPtr, primLen);
+ id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
+ (RsAllocation *)vtxPtr, vtxLen,
+ (RsAllocation *)idxPtr, idxLen,
+ (uint32_t *)primPtr, primLen);
free(vtxPtr);
free(idxPtr);
- _env->ReleaseLongArrayElements(_vtx, jVtxPtr, 0);
- _env->ReleaseLongArrayElements(_idx, jIdxPtr, 0);
- _env->ReleaseIntArrayElements(_prim, primPtr, 0);
+
+cleanupMesh:
+ if (jVtxPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_vtx, jVtxPtr, 0);
+ }
+ if (jIdxPtr != nullptr) {
+ _env->ReleaseLongArrayElements(_idx, jIdxPtr, 0);
+ }
+ if (primPtr != nullptr) {
+ _env->ReleaseIntArrayElements(_prim, primPtr, 0);
+ }
+
return id;
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 499b706..6d0d9e9 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1672,6 +1672,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
if (mBluetoothBinder == null) {
writer.println("Bluetooth Service not connected");
} else {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6716a47..574b9db 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1902,7 +1902,7 @@
return false;
}
- cancelInitializingActivities();
+ mStackSupervisor.cancelInitializingActivities();
// Find the first activity that is not finishing.
final ActivityRecord next = topRunningActivityLocked();
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 662c51e..c143474 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -908,6 +908,15 @@
}
}
+ void cancelInitializingActivities() {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ stacks.get(stackNdx).cancelInitializingActivities();
+ }
+ }
+ }
+
void reportActivityVisibleLocked(ActivityRecord r) {
sendWaitingVisibleReportLocked(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index cca6fc5..1166ae1 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1397,7 +1397,7 @@
}
intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
- } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+ } else if (!mStartActivity.intent.filterEquals(intentActivity.intent)) {
// In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance on top.
mAddingToTask = true;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 484b0e9..12c70a3 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -23,11 +23,13 @@
import android.app.Notification;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
+import android.os.Build;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -146,6 +148,22 @@
importance = IMPORTANCE_DEFAULT;
}
+ try {
+ final ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
+ sbn.getPackageName(), 0);
+ if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.N) {
+ if (isNoisy) {
+ if (importance >= IMPORTANCE_HIGH) {
+ importance = IMPORTANCE_MAX;
+ } else {
+ importance = IMPORTANCE_HIGH;
+ }
+ }
+ }
+ } catch (NameNotFoundException e) {
+ // oh well.
+ }
+
if (n.fullScreenIntent != null) {
importance = IMPORTANCE_MAX;
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c6613f5..8d75f60 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -346,8 +346,7 @@
String packageName = component.getPackageName();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setSourceBounds(sourceBounds);
mContext.startActivityAsUser(intent, opts, user);
} finally {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 76d6b28..117c663 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1749,16 +1749,6 @@
}
}
- private boolean isPackageInstalled(String pkg, int userId) {
- final ApplicationInfo info = mPm.getApplicationInfo(pkg,
- PackageManager.GET_UNINSTALLED_PACKAGES,
- userId);
- if (info == null || (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
- return false;
- }
- return true;
- }
-
/**
* Removes the app restrictions file for a specific package and user id, if it exists.
*/
@@ -2210,20 +2200,18 @@
}
}
- if (isPackageInstalled(packageName, userId)) {
- // Notify package of changes via an intent - only sent to explicitly registered receivers.
- Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
- changeIntent.setPackage(packageName);
- changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(changeIntent, new UserHandle(userId));
- }
+ // Notify package of changes via an intent - only sent to explicitly registered receivers.
+ Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+ changeIntent.setPackage(packageName);
+ changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
}
private int getUidForPackage(String packageName) {
long ident = Binder.clearCallingIdentity();
try {
return mContext.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES).uid;
+ PackageManager.MATCH_UNINSTALLED_PACKAGES).uid;
} catch (NameNotFoundException nnfe) {
return -1;
} finally {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 412a455..685403c 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -27,6 +27,8 @@
import com.android.server.wm.DimLayer.DimLayerUser;
+import java.util.ArrayList;
+
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.view.WindowManager.DOCKED_BOTTOM;
@@ -77,7 +79,17 @@
}
void setResizing(boolean resizing) {
- mResizing = resizing;
+ if (mResizing != resizing) {
+ mResizing = resizing;
+ resetDragResizingChangeReported();
+ }
+ }
+
+ private void resetDragResizingChangeReported() {
+ final WindowList windowList = mDisplayContent.getWindowList();
+ for (int i = windowList.size() - 1; i >= 0; i--) {
+ windowList.get(i).resetDragResizingChangeReported();
+ }
}
void setWindow(WindowState window) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4167ac4..fe55e80 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -536,7 +536,20 @@
}
void setDragResizing(boolean dragResizing) {
- mDragResizing = dragResizing;
+ if (mDragResizing != dragResizing) {
+ mDragResizing = dragResizing;
+ resetDragResizingChangeReported();
+ }
+ }
+
+ void resetDragResizingChangeReported() {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ win.resetDragResizingChangeReported();
+ }
+ }
}
boolean isDragResizing() {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7244676..d169b34 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -919,6 +919,16 @@
return mDragResizing;
}
+ private void setDragResizingLocked(boolean resizing) {
+ if (mDragResizing == resizing) {
+ return;
+ }
+ mDragResizing = resizing;
+ for (int i = mTasks.size() - 1; i >= 0 ; i--) {
+ mTasks.get(i).resetDragResizingChangeReported();
+ }
+ }
+
@Override // AnimatesBounds
public boolean setSize(Rect bounds) {
synchronized (mService.mWindowMap) {
@@ -936,14 +946,14 @@
@Override // AnimatesBounds
public void onAnimationStart() {
synchronized (mService.mWindowMap) {
- mDragResizing = true;
+ setDragResizingLocked(true);
}
}
@Override // AnimatesBounds
public void onAnimationEnd() {
synchronized (mService.mWindowMap) {
- mDragResizing = false;
+ setDragResizingLocked(false);
mService.requestTraversal();
}
if (mStackId == PINNED_STACK_ID) {
@@ -968,4 +978,4 @@
public void getFullScreenBounds(Rect bounds) {
getDisplayContent().getContentRect(bounds);
}
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c8f5dda..5cd14c9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8839,7 +8839,8 @@
Slog.v(TAG_WM, "Win " + w + " config changed: "
+ mCurConfiguration);
}
- final boolean dragResizingChanged = w.isDragResizeChanged();
+ final boolean dragResizingChanged = w.isDragResizeChanged()
+ && !w.isDragResizingChangeReported();
if (localLOGV) Slog.v(TAG_WM, "Resizing " + w
+ ": configChanged=" + configChanged
+ " dragResizingChanged=" + dragResizingChanged
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 37c8a7e..bea333b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -161,6 +161,7 @@
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
boolean mDragResizing;
+ boolean mDragResizingChangeReported;
int mResizeMode;
RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -2103,6 +2104,7 @@
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
reportDraw, newConfig, getBackdropFrame(frame),
isDragResizeChanged() /* forceRelayout */);
+ mDragResizingChangeReported = true;
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -2137,6 +2139,20 @@
return mDragResizing != computeDragResizing();
}
+ /**
+ * @return Whether we reported a drag resize change to the application or not already.
+ */
+ boolean isDragResizingChangeReported() {
+ return mDragResizingChangeReported;
+ }
+
+ /**
+ * Resets the state whether we reported a drag resize change to the app.
+ */
+ void resetDragResizingChangeReported() {
+ mDragResizingChangeReported = false;
+ }
+
int getResizeMode() {
return mResizeMode;
}
@@ -2161,7 +2177,11 @@
}
void setDragResizing() {
- mDragResizing = computeDragResizing();
+ final boolean resizing = computeDragResizing();
+ if (resizing == mDragResizing) {
+ return;
+ }
+ mDragResizing = resizing;
mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
? DRAG_RESIZE_MODE_DOCKED_DIVIDER
: DRAG_RESIZE_MODE_FREEFORM;
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 44be671..2373754 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -155,10 +155,6 @@
* Do not place scans in the chip's scan history buffer
*/
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
- /**
- * report full scan results and completion event to the context hub
- */
- public static final int REPORT_EVENT_CONTEXT_HUB = (1 << 3);
/**
* scan configuration parameters to be sent to {@link #startBackgroundScan}