Use SurfaceView to render grid preview
Demo: https://drive.google.com/open?id=1wQ8dT5bfTxSh-NRQpNBwTCkKOtOOUMPj
Bug: 150224413
Test: Manual
Change-Id: I006055da5e372029ecf99c4c3aac6d866688ef41
diff --git a/res/layout/grid_preview_card.xml b/res/layout/grid_preview_card.xml
index ae66b83..90b5578 100644
--- a/res/layout/grid_preview_card.xml
+++ b/res/layout/grid_preview_card.xml
@@ -24,6 +24,12 @@
android:id="@+id/grid_preview_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/primary_color"/>
+ android:background="@color/primary_color" />
+
+ <SurfaceView
+ android:id="@+id/grid_preview_surface"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/primary_color" />
</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/src/com/android/customization/model/grid/GridOptionsManager.java b/src/com/android/customization/model/grid/GridOptionsManager.java
index 1599dde..a334f5e 100644
--- a/src/com/android/customization/model/grid/GridOptionsManager.java
+++ b/src/com/android/customization/model/grid/GridOptionsManager.java
@@ -16,6 +16,8 @@
package com.android.customization.model.grid;
import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -23,7 +25,6 @@
import com.android.customization.model.CustomizationManager;
import com.android.customization.module.ThemesUserEventLogger;
-import java.util.Collections;
import java.util.List;
/**
@@ -60,7 +61,17 @@
new FetchTask(mProvider, callback).execute();
}
- private static class FetchTask extends AsyncTask<Void, Void, List<GridOption>> {
+ /** See if using surface view to render grid options */
+ public boolean usesSurfaceView() {
+ return mProvider.usesSurfaceView();
+ }
+
+ /** Call through content provider API to render preview */
+ public void renderPreview(Bundle bundle, String gridName) {
+ mProvider.renderPreview(gridName, bundle);
+ }
+
+ private static class FetchTask extends AsyncTask<Void, Void, Pair<List<GridOption>, String>> {
private final LauncherGridOptionsProvider mProvider;
@Nullable private final OptionsFetchedListener<GridOption> mCallback;
@@ -71,15 +82,16 @@
}
@Override
- protected List<GridOption> doInBackground(Void[] params) {
+ protected Pair<List<GridOption>, String> doInBackground(Void[] params) {
return mProvider.fetch(false);
}
@Override
- protected void onPostExecute(List<GridOption> gridOptions) {
+ protected void onPostExecute(Pair<List<GridOption>, String> gridOptionsResult) {
if (mCallback != null) {
- if (gridOptions != null && !gridOptions.isEmpty()) {
- mCallback.onOptionsLoaded(gridOptions);
+ if (gridOptionsResult != null && gridOptionsResult.first != null
+ && !gridOptionsResult.first.isEmpty()) {
+ mCallback.onOptionsLoaded(gridOptionsResult.first);
} else {
mCallback.onError(null);
}
diff --git a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
index 7c7f8d4..8eb7383 100644
--- a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
+++ b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
@@ -25,12 +25,16 @@
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.text.TextUtils;
+import android.util.Pair;
+import android.view.SurfaceView;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.customization.model.ResourceConstants;
+import com.android.systemui.shared.system.SurfaceViewRequestUtils;
import com.android.wallpaper.R;
import com.bumptech.glide.Glide;
@@ -53,10 +57,14 @@
private static final String COL_PREVIEW_COUNT = "preview_count";
private static final String COL_IS_DEFAULT = "is_default";
+ private static final String METHOD_GET_PREVIEW = "get_preview";
+ private static final String METADATA_KEY_PREVIEW_VERSION = "preview_version";
+
private final Context mContext;
private final String mGridProviderAuthority;
private final ProviderInfo mProviderInfo;
private List<GridOption> mOptions;
+ private String mVersion;
public LauncherGridOptionsProvider(Context context, String authorityMetadataKey) {
mContext = context;
@@ -78,18 +86,23 @@
return mProviderInfo != null;
}
+ boolean usesSurfaceView() {
+ // If no version code is returned, fall back to V1.
+ return TextUtils.equals(mVersion, "V2");
+ }
+
/**
* Retrieve the available grids.
* @param reload whether to reload grid options if they're cached.
*/
@WorkerThread
@Nullable
- List<GridOption> fetch(boolean reload) {
+ Pair<List<GridOption>, String> fetch(boolean reload) {
if (!areGridsAvailable()) {
return null;
}
if (mOptions != null && !reload) {
- return mOptions;
+ return Pair.create(mOptions, mVersion);
}
Uri optionsUri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
@@ -100,6 +113,7 @@
String iconPath = mContext.getResources().getString(Resources.getSystem().getIdentifier(
ResourceConstants.CONFIG_ICON_MASK, "string", ResourceConstants.ANDROID_PACKAGE));
try (Cursor c = resolver.query(optionsUri, null, null, null, null)) {
+ mVersion = c.getExtras().getString(METADATA_KEY_PREVIEW_VERSION);
mOptions = new ArrayList<>();
while(c.moveToNext()) {
String name = c.getString(c.getColumnIndex(COL_NAME));
@@ -120,8 +134,26 @@
Glide.get(mContext).clearDiskCache();
} catch (Exception e) {
mOptions = null;
+ mVersion = null;
}
- return mOptions;
+ return Pair.create(mOptions, mVersion);
+ }
+
+ /**
+ * Request rendering of home screen preview via Launcher to Wallpaper using SurfaceView
+ * @param name the grid option name
+ * @param bundle surface view request bundle generated from
+ * {@link SurfaceViewRequestUtils#createSurfaceBundle(SurfaceView)}.
+ */
+ void renderPreview(String name, Bundle bundle) {
+ Uri preview = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(mProviderInfo.authority)
+ .appendPath(PREVIEW)
+ .appendPath(name)
+ .build();
+ bundle.putString("name", name);
+ mContext.getContentResolver().call(preview, METHOD_GET_PREVIEW, null, bundle);
}
int applyGrid(String name) {
diff --git a/src/com/android/customization/picker/grid/GridFragment.java b/src/com/android/customization/picker/grid/GridFragment.java
index 49a3771..7a01f26 100644
--- a/src/com/android/customization/picker/grid/GridFragment.java
+++ b/src/com/android/customization/picker/grid/GridFragment.java
@@ -26,6 +26,8 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
@@ -45,6 +47,7 @@
import com.android.customization.picker.BasePreviewAdapter;
import com.android.customization.picker.BasePreviewAdapter.PreviewPage;
import com.android.customization.widget.OptionSelectorController;
+import com.android.systemui.shared.system.SurfaceViewRequestUtils;
import com.android.wallpaper.R;
import com.android.wallpaper.asset.Asset;
import com.android.wallpaper.asset.ContentUriAsset;
@@ -246,13 +249,18 @@
private final int mRows;
private final Activity mActivity;
- private ImageView mPreview;
+ private final String mName;
- private GridPreviewPage(Activity activity, int id, Uri previewUri, int rows, int cols) {
+ private ImageView mPreview;
+ private SurfaceView mPreviewSurface;
+
+ private GridPreviewPage(Activity activity, int id, Uri previewUri, String name, int rows,
+ int cols) {
super(null);
mPageId = id;
mPreviewAsset = new ContentUriAsset(activity, previewUri,
RequestOptions.fitCenterTransform());
+ mName = name;
mRows = rows;
mCols = cols;
mActivity = activity;
@@ -260,23 +268,48 @@
@Override
public void setCard(CardView card) {
- super.setCard(card);
- mPreview = card.findViewById(R.id.grid_preview_image);
+ super.setCard(card);
+ mPreview = card.findViewById(R.id.grid_preview_image);
+ mPreviewSurface = card.findViewById(R.id.grid_preview_surface);
}
public void bindPreviewContent() {
Resources resources = card.getResources();
bindWallpaperIfAvailable();
- mPreviewAsset.loadDrawableWithTransition(mActivity,
- mPreview /* imageView */,
- PREVIEW_FADE_DURATION_MS /* duration */,
- null /* drawableLoadedListener */,
- resources.getColor(android.R.color.transparent, null) /* placeHolderColorJ */);
+ final boolean usesSurfaceViewForPreview = mGridManager.usesSurfaceView();
+ mPreview.setVisibility(usesSurfaceViewForPreview ? View.GONE : View.VISIBLE);
+ mPreviewSurface.setVisibility(usesSurfaceViewForPreview ? View.VISIBLE : View.GONE);
+ if (usesSurfaceViewForPreview) {
+ mPreviewSurface.setZOrderOnTop(true);
+ mPreviewSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ Bundle bundle = SurfaceViewRequestUtils.createSurfaceBundle(
+ mPreviewSurface);
+ mGridManager.renderPreview(bundle, mName);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {}
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {}
+ });
+ } else {
+ mPreviewAsset.loadDrawableWithTransition(mActivity,
+ mPreview /* imageView */,
+ PREVIEW_FADE_DURATION_MS /* duration */,
+ null /* drawableLoadedListener */,
+ resources.getColor(android.R.color.transparent,
+ null) /* placeHolderColorJ */);
+ }
}
void bindWallpaperIfAvailable() {
if (card != null && mCardBackground != null) {
mPreview.setBackground(mCardBackground);
+ mPreviewSurface.setBackground(mCardBackground);
}
}
}
@@ -292,7 +325,7 @@
for (int i = 0; i < gridOption.previewPagesCount; i++) {
addPage(new GridPreviewPage(getActivity(), i,
gridOption.previewImageUri.buildUpon().appendPath("" + i).build(),
- gridOption.rows, gridOption.cols));
+ gridOption.name, gridOption.rows, gridOption.cols));
}
}