Save inner RecyclerView's state

The scroll position was being lost when navigating away from the list
and back again.

Bug: 135700452
Test: Manually
Change-Id: Ie73a911c249574a8109cc6beaaa041c13e4f1e8b
diff --git a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
index 08ba31b..71adcf2 100644
--- a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
+++ b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerView.java
@@ -21,8 +21,11 @@
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 
@@ -49,8 +52,6 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "PagedRecyclerView";
 
-    private Context mContext;
-
     private final CarUxRestrictionsUtil mCarUxRestrictionsUtil;
     private final CarUxRestrictionsUtil.OnUxRestrictionsChangedListener mListener;
 
@@ -227,26 +228,19 @@
             return;
         }
 
-        mContext = context;
-        mNestedRecyclerView = new RecyclerView(mContext, attrs,
+        mNestedRecyclerView = new RecyclerView(context, attrs,
                 R.style.PagedRecyclerView_NestedRecyclerView);
 
-        PagedRecyclerViewLayoutManager layoutManager = new PagedRecyclerViewLayoutManager(context);
-        super.setLayoutManager(layoutManager);
-
-        PagedRecyclerViewAdapter adapter = new PagedRecyclerViewAdapter();
-        super.setAdapter(adapter);
-
+        super.setLayoutManager(new PagedRecyclerViewLayoutManager(context));
+        super.setAdapter(new PagedRecyclerViewAdapter());
         super.setNestedScrollingEnabled(false);
         super.setClipToPadding(false);
 
         // Gutter
-        int defaultGutterSize = getResources().getDimensionPixelSize(R.dimen.car_scroll_bar_margin);
         mGutter = a.getInt(R.styleable.PagedRecyclerView_gutter, Gutter.BOTH);
-        mGutterSize = defaultGutterSize;
+        mGutterSize = getResources().getDimensionPixelSize(R.dimen.car_scroll_bar_margin);
 
-        int carMargin = mContext.getResources().getDimensionPixelSize(
-                R.dimen.car_scroll_bar_margin);
+        int carMargin = getResources().getDimensionPixelSize(R.dimen.car_scroll_bar_margin);
         mScrollBarContainerWidth = a.getDimensionPixelSize(
                 R.styleable.PagedRecyclerView_scrollBarContainerWidth, carMargin);
 
@@ -516,7 +510,9 @@
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     public void layoutBothForTesting(int l, int t, int r, int b) {
         super.layout(l, t, r, b);
-        mNestedRecyclerView.layout(l, t, r, b);
+        if (mScrollBarEnabled) {
+            mNestedRecyclerView.layout(l, t, r, b);
+        }
     }
 
     @Override
@@ -562,14 +558,14 @@
     private void createScrollBarFromConfig() {
         if (DEBUG) Log.d(TAG, "createScrollBarFromConfig");
         final String clsName = mScrollBarClass == null
-                ? mContext.getString(R.string.config_scrollBarComponent) : mScrollBarClass;
+                ? getContext().getString(R.string.config_scrollBarComponent) : mScrollBarClass;
         if (clsName == null || clsName.length() == 0) {
             throw andLog("No scroll bar component configured", null);
         }
 
         Class<?> cls;
         try {
-            cls = mContext.getClassLoader().loadClass(clsName);
+            cls = getContext().getClassLoader().loadClass(clsName);
         } catch (Throwable t) {
             throw andLog("Error loading scroll bar component: " + clsName, t);
         }
@@ -579,7 +575,7 @@
             throw andLog("Error creating scroll bar component: " + clsName, t);
         }
 
-        mScrollBarUI.initialize(mContext, mNestedRecyclerView, mScrollBarContainerWidth,
+        mScrollBarUI.initialize(getContext(), mNestedRecyclerView, mScrollBarContainerWidth,
                 mScrollBarPosition, mScrollBarAboveRecyclerView);
 
         mScrollBarUI.setPadding(mScrollBarPaddingStart, mScrollBarPaddingEnd);
@@ -639,4 +635,61 @@
         Log.e(TAG, msg, t);
         throw new RuntimeException(msg, t);
     }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState, getContext());
+        if (mScrollBarEnabled) {
+            mNestedRecyclerView.saveHierarchyState(ss.mNestedRecyclerViewState);
+        }
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            Log.w(TAG, "onRestoreInstanceState called with an unsupported state");
+            super.onRestoreInstanceState(state);
+        } else {
+            SavedState ss = (SavedState) state;
+            super.onRestoreInstanceState(ss.getSuperState());
+            if (mScrollBarEnabled) {
+                mNestedRecyclerView.restoreHierarchyState(ss.mNestedRecyclerViewState);
+            }
+        }
+    }
+
+    static class SavedState extends BaseSavedState {
+        SparseArray mNestedRecyclerViewState;
+        Context mContext;
+
+        SavedState(Parcelable superState, Context c) {
+            super(superState);
+            mContext = c;
+            mNestedRecyclerViewState = new SparseArray();
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            mNestedRecyclerViewState = in.readSparseArray(mContext.getClassLoader());
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeSparseArray(mNestedRecyclerViewState);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
 }
diff --git a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerViewAdapter.java b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerViewAdapter.java
index 623a3d4..bc35a37 100644
--- a/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerViewAdapter.java
+++ b/car-apps-common/src/com/android/car/apps/common/widget/PagedRecyclerViewAdapter.java
@@ -25,18 +25,11 @@
 
 import com.android.car.apps.common.R;
 
-import java.util.ArrayList;
-
 /**
  * The adapter for the parent recyclerview in {@link PagedRecyclerView} widget.
  */
 final class PagedRecyclerViewAdapter
         extends RecyclerView.Adapter<PagedRecyclerViewAdapter.NestedRowViewHolder> {
-    private ArrayList<String> mItem = new ArrayList<>();
-
-    PagedRecyclerViewAdapter() {
-        this.mItem.add("nested_RecyclerView");
-    }
 
     @Override
     public PagedRecyclerViewAdapter.NestedRowViewHolder onCreateViewHolder(ViewGroup parent,
@@ -55,7 +48,7 @@
     // Return the size of your dataset (invoked by the layout manager)
     @Override
     public int getItemCount() {
-        return mItem.size();
+        return 1;
     }
 
     /**