Fullscreen image preview (Part 1)

Posting to unblock live wallpaper development

Bug: 151285903
Test: https://screenshot.googleplex.com/iOp6705ZVUU (Filed b/155042852 for extra white space in the bottom sheet)

Change-Id: I8632cb1ea0585474af09a6e316a8b08a7c7e2938
diff --git a/res/layout/fragment_image_preview_v2.xml b/res/layout/fragment_image_preview_v2.xml
new file mode 100644
index 0000000..041db44
--- /dev/null
+++ b/res/layout/fragment_image_preview_v2.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="?android:colorPrimary">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginBottom="@dimen/bottom_navbar_height"
+        android:orientation="vertical">
+
+        <include layout="@layout/section_header" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:orientation="vertical">
+
+            <FrameLayout
+                android:id="@+id/wallpaper_container"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <SurfaceView
+                    android:id="@+id/wallpaper_surface"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent" />
+
+                <ImageView
+                    android:id="@+id/low_res_image"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:scaleType="centerCrop"
+                    android:background="@android:color/black" />
+
+                <com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
+                    android:id="@+id/full_res_image"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent" />
+
+                <androidx.core.widget.ContentLoadingProgressBar
+                    android:id="@+id/loading_indicator"
+                    style="@android:style/Widget.DeviceDefault.ProgressBar"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:indeterminate="true"/>
+            </FrameLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical">
+
+                <com.android.wallpaper.picker.TouchForwardingLayout
+                    android:id="@+id/touch_forwarding_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_weight="1">
+
+                    <FrameLayout
+                        android:id="@+id/workspace_container"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:background="@color/fullscreen_preview_background">
+
+                        <androidx.cardview.widget.CardView
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent">
+
+                            <SurfaceView
+                                android:id="@+id/workspace_surface"
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent" />
+                        </androidx.cardview.widget.CardView>
+                    </FrameLayout>
+                </com.android.wallpaper.picker.TouchForwardingLayout>
+
+                <LinearLayout
+                    android:id="@+id/tabs_container"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@color/fullscreen_preview_background"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:id="@+id/lock"
+                        android:layout_width="wrap_content"
+                        android:layout_height="64dp"
+                        android:layout_weight="1"
+                        android:paddingTop="20dp"
+                        android:paddingBottom="20dp"
+                        android:gravity="center"
+                        android:text="@string/lock_screen_message" />
+
+                    <TextView
+                        android:id="@+id/home"
+                        android:layout_width="wrap_content"
+                        android:layout_height="64dp"
+                        android:layout_weight="1"
+                        android:paddingTop="20dp"
+                        android:paddingBottom="20dp"
+                        android:gravity="center"
+                        android:text="@string/home_screen_message" />
+                </LinearLayout>
+            </LinearLayout>
+        </FrameLayout>
+
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone">
+
+            <androidx.coordinatorlayout.widget.CoordinatorLayout
+                android:id="@+id/coordinator_layout"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="bottom">
+
+                <FrameLayout
+                    android:id="@+id/bottom_sheet"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@drawable/preview_bottom_sheet_background"
+                    android:theme="@style/WallpaperPicker.BottomPaneStyle"
+                    app:behavior_peekHeight="@dimen/preview_attribution_pane_collapsed_height"
+                    app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
+                    <include
+                        layout="@layout/preview_page_info"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"/>
+                </FrameLayout>
+
+            </androidx.coordinatorlayout.widget.CoordinatorLayout>
+
+        </FrameLayout>
+    </LinearLayout>
+
+    <include layout="@layout/bottom_action_bar" />
+
+</FrameLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c8599c9..f44bdaa 100755
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -36,6 +36,7 @@
 
     <color name="preview_pager_arrow_disabled">@android:color/darker_gray</color>
     <color name="preview_pager_background">@color/secondary_color</color>
+    <color name="fullscreen_preview_background">@color/secondary_color</color>
     <color name="google_grey900">#202124</color>
 
     <color name="google_grey700">#5f6368</color>
diff --git a/src/com/android/wallpaper/picker/ImagePreviewFragment.java b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
index 4620954..83af285 100755
--- a/src/com/android/wallpaper/picker/ImagePreviewFragment.java
+++ b/src/com/android/wallpaper/picker/ImagePreviewFragment.java
@@ -15,6 +15,13 @@
  */
 package com.android.wallpaper.picker;
 
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
+import static com.android.wallpaper.widget.BottomActionBar.BottomAction.EDIT;
+import static com.android.wallpaper.widget.BottomActionBar.BottomAction.INFORMATION;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
@@ -26,13 +33,25 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.TextView;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+import androidx.cardview.widget.CardView;
 import androidx.fragment.app.FragmentActivity;
 
 import com.android.wallpaper.R;
@@ -40,8 +59,12 @@
 import com.android.wallpaper.model.WallpaperInfo;
 import com.android.wallpaper.module.WallpaperPersister.Destination;
 import com.android.wallpaper.module.WallpaperPersister.SetWallpaperCallback;
+import com.android.wallpaper.util.PreviewUtils;
 import com.android.wallpaper.util.ScreenSizeCalculator;
+import com.android.wallpaper.util.SurfaceViewUtils;
+import com.android.wallpaper.util.TileSizeCalculator;
 import com.android.wallpaper.util.WallpaperCropUtils;
+import com.android.wallpaper.widget.BottomActionBar;
 
 import com.bumptech.glide.Glide;
 import com.bumptech.glide.MemoryCategory;
@@ -49,6 +72,9 @@
 import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Fragment which displays the UI for previewing an individual static wallpaper and its attribution
  * information.
@@ -57,12 +83,28 @@
 
     private static final float DEFAULT_WALLPAPER_MAX_ZOOM = 8f;
 
+    private static final int MODE_DEFAULT = 0;
+    private static final int MODE_SHOW_TABS = 1;
+
+    @IntDef({MODE_DEFAULT, MODE_SHOW_TABS})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Mode {}
+
+    private @Mode int mMode = MODE_DEFAULT;
+
     private SubsamplingScaleImageView mFullResImageView;
     private Asset mWallpaperAsset;
     private Point mDefaultCropSurfaceSize;
     private Point mScreenSize;
     private Point mRawWallpaperSize; // Native size of wallpaper image.
     private ImageView mLowResImageView;
+    private TouchForwardingLayout mTouchForwardingLayout;
+    private FrameLayout mWorkspaceContainer;
+    private SurfaceView mWorkspaceSurface;
+    private SurfaceView mWallpaperSurface;
+    private View mTabs;
+    private PreviewUtils mPreviewUtils;
+    private BottomActionBar mBottomActionBar;
     private InfoPageController mInfoPageController;
 
     @Override
@@ -73,7 +115,7 @@
 
     @Override
     protected int getLayoutResId() {
-        return R.layout.fragment_image_preview;
+        return USE_NEW_UI ? R.layout.fragment_image_preview_v2 : R.layout.fragment_image_preview;
     }
 
 
@@ -92,21 +134,46 @@
         View view = super.onCreateView(inflater, container, savedInstanceState);
 
         Activity activity = requireActivity();
+        mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
+                activity.getWindowManager().getDefaultDisplay());
 
-        mFullResImageView = view.findViewById(R.id.full_res_image);
+        mLowResImageView = view.findViewById(R.id.low_res_image);
+        if (USE_NEW_UI) {
+            // TODO: Switch to use AppbarFragment functionality to setTitle when switching
+            // PreviewFragment to extend AppbarFragment
+            Toolbar toolbar = view.findViewById(R.id.toolbar);
+            TextView toolbarTitleView = toolbar.findViewById(R.id.custom_toolbar_title);
+            toolbarTitleView.setText((R.string.preview));
+            // TODO: Consider moving some part of this to the base class when live preview is ready.
+            mTouchForwardingLayout = view.findViewById(R.id.touch_forwarding_layout);
+            mWorkspaceContainer = mTouchForwardingLayout.findViewById(R.id.workspace_container);
+            mWorkspaceSurface = mWorkspaceContainer.findViewById(R.id.workspace_surface);
+            mWallpaperSurface = view.findViewById(R.id.wallpaper_surface);
+            mTabs = view.findViewById(R.id.tabs_container);
+            mPreviewUtils = new PreviewUtils(getContext(),
+                    getString(R.string.grid_control_metadata_name));
+            mBottomActionBar = view.findViewById(R.id.bottom_actionbar);
+            mBottomActionBar.showActionsOnly(INFORMATION, EDIT, APPLY);
+            mBottomActionBar.bindBackButtonToSystemBackKey(getActivity());
+            mBottomActionBar.show();
+            view.measure(makeMeasureSpec(mScreenSize.x, EXACTLY),
+                    makeMeasureSpec(mScreenSize.y, EXACTLY));
+
+            renderImageWallpaper();
+            setupPreview();
+            renderWorkspaceSurface();
+        } else {
+            mFullResImageView = view.findViewById(R.id.full_res_image);
+        }
 
         mInfoPageController = new InfoPageController(view.findViewById(R.id.page_info),
                 mPreviewMode);
 
-        mLowResImageView = view.findViewById(R.id.low_res_image);
-
         // Trim some memory from Glide to make room for the full-size image in this fragment.
         Glide.get(activity).setMemoryCategory(MemoryCategory.LOW);
 
         mDefaultCropSurfaceSize = WallpaperCropUtils.getDefaultCropSurfaceSize(
                 getResources(), activity.getWindowManager().getDefaultDisplay());
-        mScreenSize = ScreenSizeCalculator.getInstance().getScreenSize(
-                activity.getWindowManager().getDefaultDisplay());
 
         // Load a low-res placeholder image if there's a thumbnail available from the asset that can
         // be shown to the user more quickly than the full-sized image.
@@ -226,7 +293,15 @@
                     }
                     getActivity().invalidateOptionsMenu();
 
-                    populateInfoPage(mInfoPageController);
+                    if (USE_NEW_UI) {
+                        if (mWallpaper != null) {
+                            mBottomActionBar.populateInfoPage(
+                                    mWallpaper.getAttributions(getContext()),
+                                    shouldShowMetadataInPreview(mWallpaper));
+                        }
+                    } else {
+                        populateInfoPage(mInfoPageController);
+                    }
                 });
     }
 
@@ -280,7 +355,9 @@
         float defaultWallpaperZoom =
                 WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mDefaultCropSurfaceSize);
         float minWallpaperZoom =
-                WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize, mScreenSize);
+                WallpaperCropUtils.calculateMinZoom(mRawWallpaperSize,
+                        USE_NEW_UI ? new Point(mTouchForwardingLayout.getWidth(),
+                                mTouchForwardingLayout.getHeight()) : mScreenSize);
 
         // Set min wallpaper zoom and max zoom on MosaicView widget.
         mFullResImageView.setMaxScale(Math.max(DEFAULT_WALLPAPER_MAX_ZOOM, defaultWallpaperZoom));
@@ -321,4 +398,120 @@
                     }
                 });
     }
+
+    private void renderWorkspaceSurface() {
+        mWorkspaceSurface.setZOrderMediaOverlay(true);
+        mWorkspaceSurface.getHolder().addCallback(mWorkspaceSurfaceCallback);
+    }
+
+    private void renderImageWallpaper() {
+        mWallpaperSurface.getHolder().addCallback(mWallpaperSurfaceCallback);
+    }
+
+    // TODO(tracyzhou): Refactor this into a utility class.
+    private final SurfaceHolder.Callback mWorkspaceSurfaceCallback = new SurfaceHolder.Callback() {
+
+        private Surface mLastSurface;
+        private Message mCallback;
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            if (mPreviewUtils.supportsPreview() && mLastSurface != holder.getSurface()) {
+                mLastSurface = holder.getSurface();
+                Bundle result = mPreviewUtils.renderPreview(
+                        SurfaceViewUtils.createSurfaceViewRequest(mWorkspaceSurface));
+                if (result != null) {
+                    mWorkspaceSurface.setChildSurfacePackage(
+                            SurfaceViewUtils.getSurfacePackage(result));
+                    mCallback = SurfaceViewUtils.getCallback(result);
+                }
+            }
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            if (mCallback != null) {
+                try {
+                    mCallback.replyTo.send(mCallback);
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                } finally {
+                    mCallback = null;
+                }
+            }
+        }
+    };
+
+    // TODO(tracyzhou): Refactor this into a utility class.
+    private final SurfaceHolder.Callback mWallpaperSurfaceCallback = new SurfaceHolder.Callback() {
+
+        private Surface mLastSurface;
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            if (mLastSurface != holder.getSurface()) {
+                mLastSurface = holder.getSurface();
+                mFullResImageView = new SubsamplingScaleImageView(getContext());
+                mFullResImageView.measure(makeMeasureSpec(mWallpaperSurface.getWidth(), EXACTLY),
+                        makeMeasureSpec(mWallpaperSurface.getHeight(), EXACTLY));
+                mFullResImageView.layout(0, 0, mWallpaperSurface.getWidth(),
+                        mWallpaperSurface.getHeight());
+                mTouchForwardingLayout.setView(mFullResImageView);
+
+                SurfaceControlViewHost host = new SurfaceControlViewHost(getContext(),
+                        getContext().getDisplay(), mWallpaperSurface.getHostToken());
+                host.setView(mFullResImageView, mFullResImageView.getWidth(),
+                        mFullResImageView.getHeight());
+                mWallpaperSurface.setChildSurfacePackage(host.getSurfacePackage());
+            }
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) { }
+    };
+
+    // TODO(chriscsli): Investigate the possibility of moving this to the base class.
+    private void setupPreview() {
+        if (USE_NEW_UI) {
+            mTabs.setVisibility(mMode == MODE_SHOW_TABS ? View.VISIBLE : View.GONE);
+
+            final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+            int containerWidth = mWorkspaceContainer.getMeasuredWidth();
+            int containerHeight = mWorkspaceContainer.getMeasuredHeight();
+
+            int topPadding = dpToPx(24, displayMetrics.density);
+            int bottomPadding = dpToPx(getBottomPaddingInDp(), displayMetrics.density);
+            double horizontalPadding = containerWidth
+                    - (containerHeight - topPadding - bottomPadding) * 1.0
+                            * displayMetrics.widthPixels / displayMetrics.heightPixels;
+            int leftPadding = (int) horizontalPadding / 2;
+            int rightPadding = (int) horizontalPadding - leftPadding;
+            mWorkspaceContainer.setPaddingRelative(leftPadding, topPadding, rightPadding,
+                    bottomPadding);
+            ((CardView) mWorkspaceSurface.getParent())
+                    .setRadius(TileSizeCalculator.getPreviewCornerRadius(
+                            getActivity(),
+                            (int) (mWorkspaceContainer.getMeasuredWidth() - horizontalPadding)));
+        }
+    }
+
+    private int getBottomPaddingInDp() {
+        switch (mMode) {
+            case MODE_SHOW_TABS:
+                return 0;
+            case MODE_DEFAULT:
+            default:
+                return 32;
+        }
+    }
+
+    private static int dpToPx(int dp, float density) {
+        return (int) (dp * density + 0.5f);
+    }
 }
diff --git a/src/com/android/wallpaper/picker/PreviewFragment.java b/src/com/android/wallpaper/picker/PreviewFragment.java
index 7c29e9d..ddbcc50 100755
--- a/src/com/android/wallpaper/picker/PreviewFragment.java
+++ b/src/com/android/wallpaper/picker/PreviewFragment.java
@@ -79,6 +79,8 @@
         SetWallpaperDialogFragment.Listener, SetWallpaperErrorDialogFragment.Listener,
         LoadWallpaperErrorDialogFragment.Listener {
 
+    protected static final boolean USE_NEW_UI = true;
+
     /**
      * User can view wallpaper and attributions in full screen, but "Set wallpaper" button is
      * hidden.
@@ -210,13 +212,15 @@
         toolbar.getNavigationIcon().setTint(getAttrColor(activity, android.R.attr.colorPrimary));
         toolbar.getNavigationIcon().setAutoMirrored(true);
 
-        ViewCompat.setPaddingRelative(toolbar,
-        /* start */ getResources().getDimensionPixelSize(
-                        R.dimen.preview_toolbar_up_button_start_padding),
-        /* top */ 0,
-        /* end */ getResources().getDimensionPixelSize(
-                        R.dimen.preview_toolbar_set_wallpaper_button_end_padding),
-        /* bottom */ 0);
+        if (!USE_NEW_UI) {
+            ViewCompat.setPaddingRelative(toolbar,
+                    /* start */ getResources().getDimensionPixelSize(
+                            R.dimen.preview_toolbar_up_button_start_padding),
+                    /* top */ 0,
+                    /* end */ getResources().getDimensionPixelSize(
+                            R.dimen.preview_toolbar_set_wallpaper_button_end_padding),
+                    /* bottom */ 0);
+        }
 
         mLoadingProgressBar = view.findViewById(getLoadingIndicatorResId());
         mLoadingProgressBar.show();
@@ -239,18 +243,21 @@
                 : savedInstanceState.getInt(KEY_BOTTOM_SHEET_STATE, STATE_EXPANDED);
         setUpBottomSheetListeners();
 
-        view.setOnApplyWindowInsetsListener((v, windowInsets) -> {
-            toolbar.setPadding(toolbar.getPaddingLeft(),
-                    toolbar.getPaddingTop() + windowInsets.getSystemWindowInsetTop(),
-                    toolbar.getPaddingRight(), toolbar.getPaddingBottom());
-            mBottomSheet.setPadding(mBottomSheet.getPaddingLeft(),
-                    mBottomSheet.getPaddingTop(), mBottomSheet.getPaddingRight(),
-                    mBottomSheet.getPaddingBottom() + windowInsets.getSystemWindowInsetBottom());
-            WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
-            builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
-                    0, windowInsets.getStableInsetRight(), 0));
-            return builder.build();
-        });
+        if (!USE_NEW_UI) {
+            view.setOnApplyWindowInsetsListener((v, windowInsets) -> {
+                toolbar.setPadding(toolbar.getPaddingLeft(),
+                        toolbar.getPaddingTop() + windowInsets.getSystemWindowInsetTop(),
+                        toolbar.getPaddingRight(), toolbar.getPaddingBottom());
+                mBottomSheet.setPadding(mBottomSheet.getPaddingLeft(),
+                        mBottomSheet.getPaddingTop(), mBottomSheet.getPaddingRight(),
+                        mBottomSheet.getPaddingBottom()
+                                + windowInsets.getSystemWindowInsetBottom());
+                WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
+                builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
+                        0, windowInsets.getStableInsetRight(), 0));
+                return builder.build();
+            });
+        }
 
         return view;
     }
@@ -580,6 +587,11 @@
                     == View.LAYOUT_DIRECTION_RTL;
     }
 
+    protected static boolean shouldShowMetadataInPreview(WallpaperInfo wallpaperInfo) {
+        android.app.WallpaperInfo wallpaperComponent = wallpaperInfo.getWallpaperComponent();
+        return wallpaperComponent == null || wallpaperComponent.getShowMetadataInPreview();
+    }
+
     protected static class InfoPageController {
 
         public static View createView(LayoutInflater inflater) {
diff --git a/src/com/android/wallpaper/picker/TouchForwardingLayout.java b/src/com/android/wallpaper/picker/TouchForwardingLayout.java
new file mode 100644
index 0000000..3b44755
--- /dev/null
+++ b/src/com/android/wallpaper/picker/TouchForwardingLayout.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.picker;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+/** A frame layout that listens to touch events and routes them to another view. */
+public class TouchForwardingLayout extends FrameLayout {
+
+    private View mView;
+
+    public TouchForwardingLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (mView != null) {
+            mView.dispatchTouchEvent(ev);
+        }
+        return true;
+    }
+
+    /** Set the view that the touch events are routed to */
+    public void setView(View view) {
+        mView = view;
+    }
+}