Bug 965622 - (Part 2) Manage empty views in PanelLayout. r=lucasr
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Tue, 15 Apr 2014 10:03:04 -0700
changeset 197074 b17e8a8c381f37134e3015ddda04801c534e3d3e
parent 197073 aa6dbd1167365ad5357dbdbb3bc4fd95c1536a4b
child 197075 e1f4243f9636ee14b7dc201a040be8694c5fb198
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslucasr
bugs965622
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 965622 - (Part 2) Manage empty views in PanelLayout. r=lucasr
mobile/android/base/home/PanelLayout.java
--- a/mobile/android/base/home/PanelLayout.java
+++ b/mobile/android/base/home/PanelLayout.java
@@ -2,38 +2,46 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+import org.mozilla.gecko.home.HomeConfig.EmptyViewConfig;
 import org.mozilla.gecko.home.HomeConfig.ItemHandler;
 import org.mozilla.gecko.home.HomeConfig.PanelConfig;
 import org.mozilla.gecko.home.HomeConfig.ViewConfig;
 import org.mozilla.gecko.util.StringUtils;
 
 import android.content.Context;
 import android.database.Cursor;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import java.lang.ref.SoftReference;
 import java.util.EnumSet;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import com.squareup.picasso.Picasso;
+
 /**
  * {@code PanelLayout} is the base class for custom layouts to be
  * used in {@code DynamicPanel}. It provides the basic framework
  * that enables custom layouts to request and reset datasets and
  * create panel views. Furthermore, it automates most of the process
  * of binding panel views with their respective datasets.
  *
  * {@code PanelLayout} abstracts the implemention details of how
@@ -259,19 +267,34 @@ abstract class PanelLayout extends Frame
             case FILTER_PUSH:
                 viewState.pushFilter(request.getFilterDetail());
                 break;
             case FILTER_POP:
                 viewState.popFilter();
                 break;
         }
 
-        final View view = viewState.getView();
-        if (view != null) {
-            maybeSetDataset(view, cursor);
+        final View activeView = viewState.getActiveView();
+        if (activeView == null) {
+            throw new IllegalStateException("No active view for view state: " + viewState.getIndex());
+        }
+
+        final ViewConfig viewConfig = viewState.getViewConfig();
+
+        final View newView;
+        if (cursor == null || cursor.getCount() == 0) {
+            newView = createEmptyView(viewConfig);
+            maybeSetDataset(activeView, null);
+        } else {
+            newView = createPanelView(viewConfig);
+            maybeSetDataset(newView, cursor);
+        }
+
+        if (activeView != newView) {
+            replacePanelView(activeView, newView);
         }
     }
 
     /**
      * Releases any references to the given dataset from all
      * existing panel views.
      */
     public final void releaseDataset(int viewIndex) {
@@ -378,49 +401,126 @@ abstract class PanelLayout extends Frame
 
     private void maybeSetDataset(View view, Cursor cursor) {
         if (view instanceof DatasetBacked) {
             final DatasetBacked dsb = (DatasetBacked) view;
             dsb.setDataset(cursor);
         }
     }
 
+    private View createEmptyView(ViewConfig viewConfig) {
+        Log.d(LOGTAG, "Creating empty view: " + viewConfig.getType());
+
+        ViewState viewState = mViewStates.get(viewConfig.getIndex());
+        if (viewState == null) {
+            throw new IllegalStateException("No view state found for view index: " + viewConfig.getIndex());
+        }
+
+        View view = viewState.getEmptyView();
+        if (view == null) {
+            view = LayoutInflater.from(getContext()).inflate(R.layout.home_empty_panel, null);
+
+            final EmptyViewConfig emptyViewConfig = viewConfig.getEmptyViewConfig();
+
+            // XXX: Refactor this into a custom view (bug 985134)
+            final String text = (emptyViewConfig == null) ? null : emptyViewConfig.getText();
+            final TextView textView = (TextView) view.findViewById(R.id.home_empty_text);
+            if (TextUtils.isEmpty(text)) {
+                textView.setText(R.string.home_default_empty);
+            } else {
+                textView.setText(text);
+            }
+
+            final String imageUrl = (emptyViewConfig == null) ? null : emptyViewConfig.getImageUrl();
+            final ImageView imageView = (ImageView) view.findViewById(R.id.home_empty_image);
+
+            if (imageUrl == null) {
+                Picasso.with(getContext())
+                       .load(R.drawable.icon_home_empty_firefox)
+                       .into(imageView);
+            } else {
+                Picasso.with(getContext())
+                       .load(imageUrl)
+                       .error(R.drawable.icon_home_empty_firefox)
+                       .into(imageView);
+            }
+
+            viewState.setEmptyView(view);
+        }
+
+        return view;
+    }
+
+    private void replacePanelView(View currentView, View newView) {
+        final ViewGroup parent = (ViewGroup) currentView.getParent();
+        parent.addView(newView, parent.indexOfChild(currentView), currentView.getLayoutParams());
+        parent.removeView(currentView);
+    }
+
     /**
      * Must be implemented by {@code PanelLayout} subclasses to define
      * what happens then the layout is first loaded. Should set initial
      * UI state and request any necessary datasets.
      */
     public abstract void load();
 
     /**
      * Represents a 'live' instance of a panel view associated with
      * the {@code PanelLayout}. Is responsible for tracking the history stack of filters.
      */
     protected class ViewState {
         private final ViewConfig mViewConfig;
         private SoftReference<View> mView;
+        private SoftReference<View> mEmptyView;
         private LinkedList<FilterDetail> mFilterStack;
 
         public ViewState(ViewConfig viewConfig) {
             mViewConfig = viewConfig;
             mView = new SoftReference<View>(null);
+            mEmptyView = new SoftReference<View>(null);
+        }
+
+        public ViewConfig getViewConfig() {
+            return mViewConfig;
         }
 
         public int getIndex() {
             return mViewConfig.getIndex();
         }
 
         public View getView() {
             return mView.get();
         }
 
         public void setView(View view) {
             mView = new SoftReference<View>(view);
         }
 
+        public View getEmptyView() {
+            return mEmptyView.get();
+        }
+
+        public void setEmptyView(View view) {
+            mEmptyView = new SoftReference<View>(view);
+        }
+
+        public View getActiveView() {
+            final View view = getView();
+            if (view != null && view.getParent() != null) {
+                return view;
+            }
+
+            final View emptyView = getEmptyView();
+            if (emptyView != null && emptyView.getParent() != null) {
+                return emptyView;
+            }
+
+            return null;
+        }
+
         public String getDatasetId() {
             return mViewConfig.getDatasetId();
         }
 
         public ItemHandler getItemHandler() {
             return mViewConfig.getItemHandler();
         }