mobile/android/base/home/HomeConfig.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.home;
     8 import org.mozilla.gecko.GeckoAppShell;
     9 import org.mozilla.gecko.GeckoEvent;
    10 import org.mozilla.gecko.R;
    11 import org.mozilla.gecko.util.ThreadUtils;
    13 import org.json.JSONArray;
    14 import org.json.JSONException;
    15 import org.json.JSONObject;
    17 import android.content.Context;
    18 import android.os.Parcel;
    19 import android.os.Parcelable;
    20 import android.text.TextUtils;
    22 import java.util.ArrayList;
    23 import java.util.Collections;
    24 import java.util.EnumSet;
    25 import java.util.HashMap;
    26 import java.util.Iterator;
    27 import java.util.LinkedList;
    28 import java.util.List;
    29 import java.util.Map;
    31 public final class HomeConfig {
    32     /**
    33      * Used to determine what type of HomeFragment subclass to use when creating
    34      * a given panel. With the exception of DYNAMIC, all of these types correspond
    35      * to a default set of built-in panels. The DYNAMIC panel type is used by
    36      * third-party services to create panels with varying types of content.
    37      */
    38     public static enum PanelType implements Parcelable {
    39         TOP_SITES("top_sites", TopSitesPanel.class),
    40         BOOKMARKS("bookmarks", BookmarksPanel.class),
    41         HISTORY("history", HistoryPanel.class),
    42         READING_LIST("reading_list", ReadingListPanel.class),
    43         DYNAMIC("dynamic", DynamicPanel.class);
    45         private final String mId;
    46         private final Class<?> mPanelClass;
    48         PanelType(String id, Class<?> panelClass) {
    49             mId = id;
    50             mPanelClass = panelClass;
    51         }
    53         public static PanelType fromId(String id) {
    54             if (id == null) {
    55                 throw new IllegalArgumentException("Could not convert null String to PanelType");
    56             }
    58             for (PanelType panelType : PanelType.values()) {
    59                 if (TextUtils.equals(panelType.mId, id.toLowerCase())) {
    60                     return panelType;
    61                 }
    62             }
    64             throw new IllegalArgumentException("Could not convert String id to PanelType");
    65         }
    67         @Override
    68         public String toString() {
    69             return mId;
    70         }
    72         public Class<?> getPanelClass() {
    73             return mPanelClass;
    74         }
    76         @Override
    77         public int describeContents() {
    78             return 0;
    79         }
    81         @Override
    82         public void writeToParcel(Parcel dest, int flags) {
    83             dest.writeInt(ordinal());
    84         }
    86         public static final Creator<PanelType> CREATOR = new Creator<PanelType>() {
    87             @Override
    88             public PanelType createFromParcel(final Parcel source) {
    89                 return PanelType.values()[source.readInt()];
    90             }
    92             @Override
    93             public PanelType[] newArray(final int size) {
    94                 return new PanelType[size];
    95             }
    96         };
    97     }
    99     public static class PanelConfig implements Parcelable {
   100         private final PanelType mType;
   101         private final String mTitle;
   102         private final String mId;
   103         private final LayoutType mLayoutType;
   104         private final List<ViewConfig> mViews;
   105         private final AuthConfig mAuthConfig;
   106         private final EnumSet<Flags> mFlags;
   108         private static final String JSON_KEY_TYPE = "type";
   109         private static final String JSON_KEY_TITLE = "title";
   110         private static final String JSON_KEY_ID = "id";
   111         private static final String JSON_KEY_LAYOUT = "layout";
   112         private static final String JSON_KEY_VIEWS = "views";
   113         private static final String JSON_KEY_AUTH_CONFIG = "authConfig";
   114         private static final String JSON_KEY_DEFAULT = "default";
   115         private static final String JSON_KEY_DISABLED = "disabled";
   117         public enum Flags {
   118             DEFAULT_PANEL,
   119             DISABLED_PANEL
   120         }
   122         public PanelConfig(JSONObject json) throws JSONException, IllegalArgumentException {
   123             final String panelType = json.optString(JSON_KEY_TYPE, null);
   124             if (TextUtils.isEmpty(panelType)) {
   125                 mType = PanelType.DYNAMIC;
   126             } else {
   127                 mType = PanelType.fromId(panelType);
   128             }
   130             mTitle = json.getString(JSON_KEY_TITLE);
   131             mId = json.getString(JSON_KEY_ID);
   133             final String layoutTypeId = json.optString(JSON_KEY_LAYOUT, null);
   134             if (layoutTypeId != null) {
   135                 mLayoutType = LayoutType.fromId(layoutTypeId);
   136             } else {
   137                 mLayoutType = null;
   138             }
   140             final JSONArray jsonViews = json.optJSONArray(JSON_KEY_VIEWS);
   141             if (jsonViews != null) {
   142                 mViews = new ArrayList<ViewConfig>();
   144                 final int viewCount = jsonViews.length();
   145                 for (int i = 0; i < viewCount; i++) {
   146                     final JSONObject jsonViewConfig = (JSONObject) jsonViews.get(i);
   147                     final ViewConfig viewConfig = new ViewConfig(i, jsonViewConfig);
   148                     mViews.add(viewConfig);
   149                 }
   150             } else {
   151                 mViews = null;
   152             }
   154             final JSONObject jsonAuthConfig = json.optJSONObject(JSON_KEY_AUTH_CONFIG);
   155             if (jsonAuthConfig != null) {
   156                 mAuthConfig = new AuthConfig(jsonAuthConfig);
   157             } else {
   158                 mAuthConfig = null;
   159             }
   161             mFlags = EnumSet.noneOf(Flags.class);
   163             if (json.optBoolean(JSON_KEY_DEFAULT, false)) {
   164                 mFlags.add(Flags.DEFAULT_PANEL);
   165             }
   167             if (json.optBoolean(JSON_KEY_DISABLED, false)) {
   168                 mFlags.add(Flags.DISABLED_PANEL);
   169             }
   171             validate();
   172         }
   174         @SuppressWarnings("unchecked")
   175         public PanelConfig(Parcel in) {
   176             mType = (PanelType) in.readParcelable(getClass().getClassLoader());
   177             mTitle = in.readString();
   178             mId = in.readString();
   179             mLayoutType = (LayoutType) in.readParcelable(getClass().getClassLoader());
   181             mViews = new ArrayList<ViewConfig>();
   182             in.readTypedList(mViews, ViewConfig.CREATOR);
   184             mAuthConfig = (AuthConfig) in.readParcelable(getClass().getClassLoader());
   186             mFlags = (EnumSet<Flags>) in.readSerializable();
   188             validate();
   189         }
   191         public PanelConfig(PanelConfig panelConfig) {
   192             mType = panelConfig.mType;
   193             mTitle = panelConfig.mTitle;
   194             mId = panelConfig.mId;
   195             mLayoutType = panelConfig.mLayoutType;
   197             mViews = new ArrayList<ViewConfig>();
   198             List<ViewConfig> viewConfigs = panelConfig.mViews;
   199             if (viewConfigs != null) {
   200                 for (ViewConfig viewConfig : viewConfigs) {
   201                     mViews.add(new ViewConfig(viewConfig));
   202                 }
   203             }
   205             mAuthConfig = panelConfig.mAuthConfig;
   206             mFlags = panelConfig.mFlags.clone();
   208             validate();
   209         }
   211         public PanelConfig(PanelType type, String title, String id) {
   212             this(type, title, id, EnumSet.noneOf(Flags.class));
   213         }
   215         public PanelConfig(PanelType type, String title, String id, EnumSet<Flags> flags) {
   216             this(type, title, id, null, null, null, flags);
   217         }
   219         public PanelConfig(PanelType type, String title, String id, LayoutType layoutType,
   220                 List<ViewConfig> views, AuthConfig authConfig, EnumSet<Flags> flags) {
   221             mType = type;
   222             mTitle = title;
   223             mId = id;
   224             mLayoutType = layoutType;
   225             mViews = views;
   226             mAuthConfig = authConfig;
   227             mFlags = flags;
   229             validate();
   230         }
   232         private void validate() {
   233             if (mType == null) {
   234                 throw new IllegalArgumentException("Can't create PanelConfig with null type");
   235             }
   237             if (TextUtils.isEmpty(mTitle)) {
   238                 throw new IllegalArgumentException("Can't create PanelConfig with empty title");
   239             }
   241             if (TextUtils.isEmpty(mId)) {
   242                 throw new IllegalArgumentException("Can't create PanelConfig with empty id");
   243             }
   245             if (mLayoutType == null && mType == PanelType.DYNAMIC) {
   246                 throw new IllegalArgumentException("Can't create a dynamic PanelConfig with null layout type");
   247             }
   249             if ((mViews == null || mViews.size() == 0) && mType == PanelType.DYNAMIC) {
   250                 throw new IllegalArgumentException("Can't create a dynamic PanelConfig with no views");
   251             }
   253             if (mFlags == null) {
   254                 throw new IllegalArgumentException("Can't create PanelConfig with null flags");
   255             }
   256         }
   258         public PanelType getType() {
   259             return mType;
   260         }
   262         public String getTitle() {
   263             return mTitle;
   264         }
   266         public String getId() {
   267             return mId;
   268         }
   270         public LayoutType getLayoutType() {
   271             return mLayoutType;
   272         }
   274         public int getViewCount() {
   275             return (mViews != null ? mViews.size() : 0);
   276         }
   278         public ViewConfig getViewAt(int index) {
   279             return (mViews != null ? mViews.get(index) : null);
   280         }
   282         public boolean isDynamic() {
   283             return (mType == PanelType.DYNAMIC);
   284         }
   286         public boolean isDefault() {
   287             return mFlags.contains(Flags.DEFAULT_PANEL);
   288         }
   290         private void setIsDefault(boolean isDefault) {
   291             if (isDefault) {
   292                 mFlags.add(Flags.DEFAULT_PANEL);
   293             } else {
   294                 mFlags.remove(Flags.DEFAULT_PANEL);
   295             }
   296         }
   298         public boolean isDisabled() {
   299             return mFlags.contains(Flags.DISABLED_PANEL);
   300         }
   302         private void setIsDisabled(boolean isDisabled) {
   303             if (isDisabled) {
   304                 mFlags.add(Flags.DISABLED_PANEL);
   305             } else {
   306                 mFlags.remove(Flags.DISABLED_PANEL);
   307             }
   308         }
   310         public AuthConfig getAuthConfig() {
   311             return mAuthConfig;
   312         }
   314         public JSONObject toJSON() throws JSONException {
   315             final JSONObject json = new JSONObject();
   317             json.put(JSON_KEY_TYPE, mType.toString());
   318             json.put(JSON_KEY_TITLE, mTitle);
   319             json.put(JSON_KEY_ID, mId);
   321             if (mLayoutType != null) {
   322                 json.put(JSON_KEY_LAYOUT, mLayoutType.toString());
   323             }
   325             if (mViews != null) {
   326                 final JSONArray jsonViews = new JSONArray();
   328                 final int viewCount = mViews.size();
   329                 for (int i = 0; i < viewCount; i++) {
   330                     final ViewConfig viewConfig = mViews.get(i);
   331                     final JSONObject jsonViewConfig = viewConfig.toJSON();
   332                     jsonViews.put(jsonViewConfig);
   333                 }
   335                 json.put(JSON_KEY_VIEWS, jsonViews);
   336             }
   338             if (mAuthConfig != null) {
   339                 json.put(JSON_KEY_AUTH_CONFIG, mAuthConfig.toJSON());
   340             }
   342             if (mFlags.contains(Flags.DEFAULT_PANEL)) {
   343                 json.put(JSON_KEY_DEFAULT, true);
   344             }
   346             if (mFlags.contains(Flags.DISABLED_PANEL)) {
   347                 json.put(JSON_KEY_DISABLED, true);
   348             }
   350             return json;
   351         }
   353         @Override
   354         public boolean equals(Object o) {
   355             if (o == null) {
   356                 return false;
   357             }
   359             if (this == o) {
   360                 return true;
   361             }
   363             if (!(o instanceof PanelConfig)) {
   364                 return false;
   365             }
   367             final PanelConfig other = (PanelConfig) o;
   368             return mId.equals(other.mId);
   369         }
   371         @Override
   372         public int describeContents() {
   373             return 0;
   374         }
   376         @Override
   377         public void writeToParcel(Parcel dest, int flags) {
   378             dest.writeParcelable(mType, 0);
   379             dest.writeString(mTitle);
   380             dest.writeString(mId);
   381             dest.writeParcelable(mLayoutType, 0);
   382             dest.writeTypedList(mViews);
   383             dest.writeParcelable(mAuthConfig, 0);
   384             dest.writeSerializable(mFlags);
   385         }
   387         public static final Creator<PanelConfig> CREATOR = new Creator<PanelConfig>() {
   388             @Override
   389             public PanelConfig createFromParcel(final Parcel in) {
   390                 return new PanelConfig(in);
   391             }
   393             @Override
   394             public PanelConfig[] newArray(final int size) {
   395                 return new PanelConfig[size];
   396             }
   397         };
   398     }
   400     public static enum LayoutType implements Parcelable {
   401         FRAME("frame");
   403         private final String mId;
   405         LayoutType(String id) {
   406             mId = id;
   407         }
   409         public static LayoutType fromId(String id) {
   410             if (id == null) {
   411                 throw new IllegalArgumentException("Could not convert null String to LayoutType");
   412             }
   414             for (LayoutType layoutType : LayoutType.values()) {
   415                 if (TextUtils.equals(layoutType.mId, id.toLowerCase())) {
   416                     return layoutType;
   417                 }
   418             }
   420             throw new IllegalArgumentException("Could not convert String id to LayoutType");
   421         }
   423         @Override
   424         public String toString() {
   425             return mId;
   426         }
   428         @Override
   429         public int describeContents() {
   430             return 0;
   431         }
   433         @Override
   434         public void writeToParcel(Parcel dest, int flags) {
   435             dest.writeInt(ordinal());
   436         }
   438         public static final Creator<LayoutType> CREATOR = new Creator<LayoutType>() {
   439             @Override
   440             public LayoutType createFromParcel(final Parcel source) {
   441                 return LayoutType.values()[source.readInt()];
   442             }
   444             @Override
   445             public LayoutType[] newArray(final int size) {
   446                 return new LayoutType[size];
   447             }
   448         };
   449     }
   451     public static enum ViewType implements Parcelable {
   452         LIST("list"),
   453         GRID("grid");
   455         private final String mId;
   457         ViewType(String id) {
   458             mId = id;
   459         }
   461         public static ViewType fromId(String id) {
   462             if (id == null) {
   463                 throw new IllegalArgumentException("Could not convert null String to ViewType");
   464             }
   466             for (ViewType viewType : ViewType.values()) {
   467                 if (TextUtils.equals(viewType.mId, id.toLowerCase())) {
   468                     return viewType;
   469                 }
   470             }
   472             throw new IllegalArgumentException("Could not convert String id to ViewType");
   473         }
   475         @Override
   476         public String toString() {
   477             return mId;
   478         }
   480         @Override
   481         public int describeContents() {
   482             return 0;
   483         }
   485         @Override
   486         public void writeToParcel(Parcel dest, int flags) {
   487             dest.writeInt(ordinal());
   488         }
   490         public static final Creator<ViewType> CREATOR = new Creator<ViewType>() {
   491             @Override
   492             public ViewType createFromParcel(final Parcel source) {
   493                 return ViewType.values()[source.readInt()];
   494             }
   496             @Override
   497             public ViewType[] newArray(final int size) {
   498                 return new ViewType[size];
   499             }
   500         };
   501     }
   503     public static enum ItemType implements Parcelable {
   504         ARTICLE("article"),
   505         IMAGE("image");
   507         private final String mId;
   509         ItemType(String id) {
   510             mId = id;
   511         }
   513         public static ItemType fromId(String id) {
   514             if (id == null) {
   515                 throw new IllegalArgumentException("Could not convert null String to ItemType");
   516             }
   518             for (ItemType itemType : ItemType.values()) {
   519                 if (TextUtils.equals(itemType.mId, id.toLowerCase())) {
   520                     return itemType;
   521                 }
   522             }
   524             throw new IllegalArgumentException("Could not convert String id to ItemType");
   525         }
   527         @Override
   528         public String toString() {
   529             return mId;
   530         }
   532         @Override
   533         public int describeContents() {
   534             return 0;
   535         }
   537         @Override
   538         public void writeToParcel(Parcel dest, int flags) {
   539             dest.writeInt(ordinal());
   540         }
   542         public static final Creator<ItemType> CREATOR = new Creator<ItemType>() {
   543             @Override
   544             public ItemType createFromParcel(final Parcel source) {
   545                 return ItemType.values()[source.readInt()];
   546             }
   548             @Override
   549             public ItemType[] newArray(final int size) {
   550                 return new ItemType[size];
   551             }
   552         };
   553     }
   555     public static enum ItemHandler implements Parcelable {
   556         BROWSER("browser"),
   557         INTENT("intent");
   559         private final String mId;
   561         ItemHandler(String id) {
   562             mId = id;
   563         }
   565         public static ItemHandler fromId(String id) {
   566             if (id == null) {
   567                 throw new IllegalArgumentException("Could not convert null String to ItemHandler");
   568             }
   570             for (ItemHandler itemHandler : ItemHandler.values()) {
   571                 if (TextUtils.equals(itemHandler.mId, id.toLowerCase())) {
   572                     return itemHandler;
   573                 }
   574             }
   576             throw new IllegalArgumentException("Could not convert String id to ItemHandler");
   577         }
   579         @Override
   580         public String toString() {
   581             return mId;
   582         }
   584         @Override
   585         public int describeContents() {
   586             return 0;
   587         }
   589         @Override
   590         public void writeToParcel(Parcel dest, int flags) {
   591             dest.writeInt(ordinal());
   592         }
   594         public static final Creator<ItemHandler> CREATOR = new Creator<ItemHandler>() {
   595             @Override
   596             public ItemHandler createFromParcel(final Parcel source) {
   597                 return ItemHandler.values()[source.readInt()];
   598             }
   600             @Override
   601             public ItemHandler[] newArray(final int size) {
   602                 return new ItemHandler[size];
   603             }
   604         };
   605     }
   607     public static class ViewConfig implements Parcelable {
   608         private final int mIndex;
   609         private final ViewType mType;
   610         private final String mDatasetId;
   611         private final ItemType mItemType;
   612         private final ItemHandler mItemHandler;
   613         private final String mBackImageUrl;
   614         private final String mFilter;
   615         private final EmptyViewConfig mEmptyViewConfig;
   616         private final EnumSet<Flags> mFlags;
   618         private static final String JSON_KEY_TYPE = "type";
   619         private static final String JSON_KEY_DATASET = "dataset";
   620         private static final String JSON_KEY_ITEM_TYPE = "itemType";
   621         private static final String JSON_KEY_ITEM_HANDLER = "itemHandler";
   622         private static final String JSON_KEY_BACK_IMAGE_URL = "backImageUrl";
   623         private static final String JSON_KEY_FILTER = "filter";
   624         private static final String JSON_KEY_EMPTY = "empty";
   625         private static final String JSON_KEY_REFRESH_ENABLED = "refreshEnabled";
   627         public enum Flags {
   628             REFRESH_ENABLED
   629         }
   631         public ViewConfig(int index, JSONObject json) throws JSONException, IllegalArgumentException {
   632             mIndex = index;
   633             mType = ViewType.fromId(json.getString(JSON_KEY_TYPE));
   634             mDatasetId = json.getString(JSON_KEY_DATASET);
   635             mItemType = ItemType.fromId(json.getString(JSON_KEY_ITEM_TYPE));
   636             mItemHandler = ItemHandler.fromId(json.getString(JSON_KEY_ITEM_HANDLER));
   637             mBackImageUrl = json.optString(JSON_KEY_BACK_IMAGE_URL, null);
   638             mFilter = json.optString(JSON_KEY_FILTER, null);
   640             final JSONObject jsonEmptyViewConfig = json.optJSONObject(JSON_KEY_EMPTY);
   641             if (jsonEmptyViewConfig != null) {
   642                 mEmptyViewConfig = new EmptyViewConfig(jsonEmptyViewConfig);
   643             } else {
   644                 mEmptyViewConfig = null;
   645             }
   647             mFlags = EnumSet.noneOf(Flags.class);
   648             if (json.optBoolean(JSON_KEY_REFRESH_ENABLED, false)) {
   649                 mFlags.add(Flags.REFRESH_ENABLED);
   650             }
   652             validate();
   653         }
   655         @SuppressWarnings("unchecked")
   656         public ViewConfig(Parcel in) {
   657             mIndex = in.readInt();
   658             mType = (ViewType) in.readParcelable(getClass().getClassLoader());
   659             mDatasetId = in.readString();
   660             mItemType = (ItemType) in.readParcelable(getClass().getClassLoader());
   661             mItemHandler = (ItemHandler) in.readParcelable(getClass().getClassLoader());
   662             mBackImageUrl = in.readString();
   663             mFilter = in.readString();
   664             mEmptyViewConfig = (EmptyViewConfig) in.readParcelable(getClass().getClassLoader());
   665             mFlags = (EnumSet<Flags>) in.readSerializable();
   667             validate();
   668         }
   670         public ViewConfig(ViewConfig viewConfig) {
   671             mIndex = viewConfig.mIndex;
   672             mType = viewConfig.mType;
   673             mDatasetId = viewConfig.mDatasetId;
   674             mItemType = viewConfig.mItemType;
   675             mItemHandler = viewConfig.mItemHandler;
   676             mBackImageUrl = viewConfig.mBackImageUrl;
   677             mFilter = viewConfig.mFilter;
   678             mEmptyViewConfig = viewConfig.mEmptyViewConfig;
   679             mFlags = viewConfig.mFlags.clone();
   681             validate();
   682         }
   684         public ViewConfig(int index, ViewType type, String datasetId, ItemType itemType,
   685                           ItemHandler itemHandler, String backImageUrl, String filter,
   686                           EmptyViewConfig emptyViewConfig, EnumSet<Flags> flags) {
   687             mIndex = index;
   688             mType = type;
   689             mDatasetId = datasetId;
   690             mItemType = itemType;
   691             mItemHandler = itemHandler;
   692             mBackImageUrl = backImageUrl;
   693             mFilter = filter;
   694             mEmptyViewConfig = emptyViewConfig;
   695             mFlags = flags;
   697             validate();
   698         }
   700         private void validate() {
   701             if (mType == null) {
   702                 throw new IllegalArgumentException("Can't create ViewConfig with null type");
   703             }
   705             if (TextUtils.isEmpty(mDatasetId)) {
   706                 throw new IllegalArgumentException("Can't create ViewConfig with empty dataset ID");
   707             }
   709             if (mItemType == null) {
   710                 throw new IllegalArgumentException("Can't create ViewConfig with null item type");
   711             }
   713             if (mItemHandler == null) {
   714                 throw new IllegalArgumentException("Can't create ViewConfig with null item handler");
   715             }
   717             if (mFlags == null) {
   718                throw new IllegalArgumentException("Can't create ViewConfig with null flags");
   719             }
   720         }
   722         public int getIndex() {
   723             return mIndex;
   724         }
   726         public ViewType getType() {
   727             return mType;
   728         }
   730         public String getDatasetId() {
   731             return mDatasetId;
   732         }
   734         public ItemType getItemType() {
   735             return mItemType;
   736         }
   738         public ItemHandler getItemHandler() {
   739             return mItemHandler;
   740         }
   742         public String getBackImageUrl() {
   743             return mBackImageUrl;
   744         }
   746         public String getFilter() {
   747             return mFilter;
   748         }
   750         public EmptyViewConfig getEmptyViewConfig() {
   751             return mEmptyViewConfig;
   752         }
   754         public boolean isRefreshEnabled() {
   755             return mFlags.contains(Flags.REFRESH_ENABLED);
   756         }
   758         public JSONObject toJSON() throws JSONException {
   759             final JSONObject json = new JSONObject();
   761             json.put(JSON_KEY_TYPE, mType.toString());
   762             json.put(JSON_KEY_DATASET, mDatasetId);
   763             json.put(JSON_KEY_ITEM_TYPE, mItemType.toString());
   764             json.put(JSON_KEY_ITEM_HANDLER, mItemHandler.toString());
   766             if (!TextUtils.isEmpty(mBackImageUrl)) {
   767                 json.put(JSON_KEY_BACK_IMAGE_URL, mBackImageUrl);
   768             }
   770             if (!TextUtils.isEmpty(mFilter)) {
   771                 json.put(JSON_KEY_FILTER, mFilter);
   772             }
   774             if (mEmptyViewConfig != null) {
   775                 json.put(JSON_KEY_EMPTY, mEmptyViewConfig.toJSON());
   776             }
   778             if (mFlags.contains(Flags.REFRESH_ENABLED)) {
   779                 json.put(JSON_KEY_REFRESH_ENABLED, true);
   780             }
   782             return json;
   783         }
   785         @Override
   786         public int describeContents() {
   787             return 0;
   788         }
   790         @Override
   791         public void writeToParcel(Parcel dest, int flags) {
   792             dest.writeInt(mIndex);
   793             dest.writeParcelable(mType, 0);
   794             dest.writeString(mDatasetId);
   795             dest.writeParcelable(mItemType, 0);
   796             dest.writeParcelable(mItemHandler, 0);
   797             dest.writeString(mBackImageUrl);
   798             dest.writeString(mFilter);
   799             dest.writeParcelable(mEmptyViewConfig, 0);
   800             dest.writeSerializable(mFlags);
   801         }
   803         public static final Creator<ViewConfig> CREATOR = new Creator<ViewConfig>() {
   804             @Override
   805             public ViewConfig createFromParcel(final Parcel in) {
   806                 return new ViewConfig(in);
   807             }
   809             @Override
   810             public ViewConfig[] newArray(final int size) {
   811                 return new ViewConfig[size];
   812             }
   813         };
   814     }
   816     public static class EmptyViewConfig implements Parcelable {
   817         private final String mText;
   818         private final String mImageUrl;
   820         private static final String JSON_KEY_TEXT = "text";
   821         private static final String JSON_KEY_IMAGE_URL = "imageUrl";
   823         public EmptyViewConfig(JSONObject json) throws JSONException, IllegalArgumentException {
   824             mText = json.optString(JSON_KEY_TEXT, null);
   825             mImageUrl = json.optString(JSON_KEY_IMAGE_URL, null);
   826         }
   828         @SuppressWarnings("unchecked")
   829         public EmptyViewConfig(Parcel in) {
   830             mText = in.readString();
   831             mImageUrl = in.readString();
   832         }
   834         public EmptyViewConfig(EmptyViewConfig emptyViewConfig) {
   835             mText = emptyViewConfig.mText;
   836             mImageUrl = emptyViewConfig.mImageUrl;
   837         }
   839         public EmptyViewConfig(String text, String imageUrl) {
   840             mText = text;
   841             mImageUrl = imageUrl;
   842         }
   844         public String getText() {
   845             return mText;
   846         }
   848         public String getImageUrl() {
   849             return mImageUrl;
   850         }
   852         public JSONObject toJSON() throws JSONException {
   853             final JSONObject json = new JSONObject();
   855             json.put(JSON_KEY_TEXT, mText);
   856             json.put(JSON_KEY_IMAGE_URL, mImageUrl);
   858             return json;
   859         }
   861         @Override
   862         public int describeContents() {
   863             return 0;
   864         }
   866         @Override
   867         public void writeToParcel(Parcel dest, int flags) {
   868             dest.writeString(mText);
   869             dest.writeString(mImageUrl);
   870         }
   872         public static final Creator<EmptyViewConfig> CREATOR = new Creator<EmptyViewConfig>() {
   873             @Override
   874             public EmptyViewConfig createFromParcel(final Parcel in) {
   875                 return new EmptyViewConfig(in);
   876             }
   878             @Override
   879             public EmptyViewConfig[] newArray(final int size) {
   880                 return new EmptyViewConfig[size];
   881             }
   882         };
   883     }
   885     public static class AuthConfig implements Parcelable {
   886         private final String mMessageText;
   887         private final String mButtonText;
   888         private final String mImageUrl;
   890         private static final String JSON_KEY_MESSAGE_TEXT = "messageText";
   891         private static final String JSON_KEY_BUTTON_TEXT = "buttonText";
   892         private static final String JSON_KEY_IMAGE_URL = "imageUrl";
   894         public AuthConfig(JSONObject json) throws JSONException, IllegalArgumentException {
   895             mMessageText = json.optString(JSON_KEY_MESSAGE_TEXT);
   896             mButtonText = json.optString(JSON_KEY_BUTTON_TEXT);
   897             mImageUrl = json.optString(JSON_KEY_IMAGE_URL, null);
   898         }
   900         @SuppressWarnings("unchecked")
   901         public AuthConfig(Parcel in) {
   902             mMessageText = in.readString();
   903             mButtonText = in.readString();
   904             mImageUrl = in.readString();
   906             validate();
   907         }
   909         public AuthConfig(AuthConfig authConfig) {
   910             mMessageText = authConfig.mMessageText;
   911             mButtonText = authConfig.mButtonText;
   912             mImageUrl = authConfig.mImageUrl;
   914             validate();
   915         }
   917         public AuthConfig(String messageText, String buttonText, String imageUrl) {
   918             mMessageText = messageText;
   919             mButtonText = buttonText;
   920             mImageUrl = imageUrl;
   922             validate();
   923         }
   925         private void validate() {
   926             if (mMessageText == null) {
   927                 throw new IllegalArgumentException("Can't create AuthConfig with null message text");
   928             }
   930             if (mButtonText == null) {
   931                 throw new IllegalArgumentException("Can't create AuthConfig with null button text");
   932             }
   933         }
   935         public String getMessageText() {
   936             return mMessageText;
   937         }
   939         public String getButtonText() {
   940             return mButtonText;
   941         }
   943         public String getImageUrl() {
   944             return mImageUrl;
   945         }
   947         public JSONObject toJSON() throws JSONException {
   948             final JSONObject json = new JSONObject();
   950             json.put(JSON_KEY_MESSAGE_TEXT, mMessageText);
   951             json.put(JSON_KEY_BUTTON_TEXT, mButtonText);
   952             json.put(JSON_KEY_IMAGE_URL, mImageUrl);
   954             return json;
   955         }
   957         @Override
   958         public int describeContents() {
   959             return 0;
   960         }
   962         @Override
   963         public void writeToParcel(Parcel dest, int flags) {
   964             dest.writeString(mMessageText);
   965             dest.writeString(mButtonText);
   966             dest.writeString(mImageUrl);
   967         }
   969         public static final Creator<AuthConfig> CREATOR = new Creator<AuthConfig>() {
   970             @Override
   971             public AuthConfig createFromParcel(final Parcel in) {
   972                 return new AuthConfig(in);
   973             }
   975             @Override
   976             public AuthConfig[] newArray(final int size) {
   977                 return new AuthConfig[size];
   978             }
   979         };
   980     }
   981    /**
   982      * Immutable representation of the current state of {@code HomeConfig}.
   983      * This is what HomeConfig returns from a load() call and takes as
   984      * input to save a new state.
   985      *
   986      * Users of {@code State} should use an {@code Iterator} to iterate
   987      * through the contained {@code PanelConfig} instances.
   988      *
   989      * {@code State} is immutable i.e. you can't add, remove, or update
   990      * contained elements directly. You have to use an {@code Editor} to
   991      * change the state, which can be created through the {@code edit()}
   992      * method.
   993      */
   994     public static class State implements Iterable<PanelConfig> {
   995         private HomeConfig mHomeConfig;
   996         private final List<PanelConfig> mPanelConfigs;
   997         private final boolean mIsDefault;
   999         State(List<PanelConfig> panelConfigs, boolean isDefault) {
  1000             this(null, panelConfigs, isDefault);
  1003         private State(HomeConfig homeConfig, List<PanelConfig> panelConfigs, boolean isDefault) {
  1004             mHomeConfig = homeConfig;
  1005             mPanelConfigs = Collections.unmodifiableList(panelConfigs);
  1006             mIsDefault = isDefault;
  1009         private void setHomeConfig(HomeConfig homeConfig) {
  1010             if (mHomeConfig != null) {
  1011                 throw new IllegalStateException("Can't set HomeConfig more than once");
  1014             mHomeConfig = homeConfig;
  1017         @Override
  1018         public Iterator<PanelConfig> iterator() {
  1019             return mPanelConfigs.iterator();
  1022         /**
  1023          * Returns whether this {@code State} instance represents the default
  1024          * {@code HomeConfig} configuration or not.
  1025          */
  1026         public boolean isDefault() {
  1027             return mIsDefault;
  1030         /**
  1031          * Creates an {@code Editor} for this state.
  1032          */
  1033         public Editor edit() {
  1034             return new Editor(mHomeConfig, this);
  1038     /**
  1039      * {@code Editor} allows you to make changes to a {@code State}. You
  1040      * can create {@code Editor} by calling {@code edit()} on the target
  1041      * {@code State} instance.
  1043      * {@code Editor} works on a copy of the {@code State} that originated
  1044      * it. This means that adding, removing, or updating panels in an
  1045      * {@code Editor} will never change the {@code State} which you
  1046      * created the {@code Editor} from. Calling {@code commit()} or
  1047      * {@code apply()} will cause the new {@code State} instance to be
  1048      * created and saved using the {@code HomeConfig} instance that
  1049      * created the source {@code State}.
  1051      * {@code Editor} is *not* thread-safe. You can only make calls on it
  1052      * from the thread where it was originally created. It will throw an
  1053      * exception if you don't follow this invariant.
  1054      */
  1055     public static class Editor implements Iterable<PanelConfig> {
  1056         private final HomeConfig mHomeConfig;
  1057         private final Map<String, PanelConfig> mConfigMap;
  1058         private final List<String> mConfigOrder;
  1059         private final List<GeckoEvent> mEventQueue;
  1060         private final Thread mOriginalThread;
  1062         private PanelConfig mDefaultPanel;
  1063         private int mEnabledCount;
  1065         private boolean mHasChanged;
  1066         private final boolean mIsFromDefault;
  1068         private Editor(HomeConfig homeConfig, State configState) {
  1069             mHomeConfig = homeConfig;
  1070             mOriginalThread = Thread.currentThread();
  1071             mConfigMap = new HashMap<String, PanelConfig>();
  1072             mConfigOrder = new LinkedList<String>();
  1073             mEventQueue = new LinkedList<GeckoEvent>();
  1074             mEnabledCount = 0;
  1076             mHasChanged = false;
  1077             mIsFromDefault = configState.isDefault();
  1079             initFromState(configState);
  1082         /**
  1083          * Initialize the initial state of the editor from the given
  1084          * {@sode State}. A HashMap is used to represent the list of
  1085          * panels as it provides fast access, and a LinkedList is used to
  1086          * keep track of order. We keep a reference to the default panel
  1087          * and the number of enabled panels to avoid iterating through the
  1088          * map every time we need those.
  1090          * @param configState The source State to load the editor from.
  1091          */
  1092         private void initFromState(State configState) {
  1093             for (PanelConfig panelConfig : configState) {
  1094                 final PanelConfig panelCopy = new PanelConfig(panelConfig);
  1096                 if (!panelCopy.isDisabled()) {
  1097                     mEnabledCount++;
  1100                 if (panelCopy.isDefault()) {
  1101                     if (mDefaultPanel == null) {
  1102                         mDefaultPanel = panelCopy;
  1103                     } else {
  1104                         throw new IllegalStateException("Multiple default panels in HomeConfig state");
  1108                 final String panelId = panelConfig.getId();
  1109                 mConfigOrder.add(panelId);
  1110                 mConfigMap.put(panelId, panelCopy);
  1113             // We should always have a defined default panel if there's
  1114             // at least one enabled panel around.
  1115             if (mEnabledCount > 0 && mDefaultPanel == null) {
  1116                 throw new IllegalStateException("Default panel in HomeConfig state is undefined");
  1120         private PanelConfig getPanelOrThrow(String panelId) {
  1121             final PanelConfig panelConfig = mConfigMap.get(panelId);
  1122             if (panelConfig == null) {
  1123                 throw new IllegalStateException("Tried to access non-existing panel: " + panelId);
  1126             return panelConfig;
  1129         private boolean isCurrentDefaultPanel(PanelConfig panelConfig) {
  1130             if (mDefaultPanel == null) {
  1131                 return false;
  1134             return mDefaultPanel.equals(panelConfig);
  1137         private void findNewDefault() {
  1138             // Pick the first panel that is neither disabled nor currently
  1139             // set as default.
  1140             for (PanelConfig panelConfig : mConfigMap.values()) {
  1141                 if (!panelConfig.isDefault() && !panelConfig.isDisabled()) {
  1142                     setDefault(panelConfig.getId());
  1143                     return;
  1147             mDefaultPanel = null;
  1150         /**
  1151          * Makes an ordered list of PanelConfigs that can be references
  1152          * or deep copied objects.
  1154          * @param deepCopy true to make deep-copied objects
  1155          * @return ordered List of PanelConfigs
  1156          */
  1157         private List<PanelConfig> makeOrderedCopy(boolean deepCopy) {
  1158             final List<PanelConfig> copiedList = new ArrayList<PanelConfig>(mConfigOrder.size());
  1159             for (String panelId : mConfigOrder) {
  1160                 PanelConfig panelConfig = mConfigMap.get(panelId);
  1161                 if (deepCopy) {
  1162                     panelConfig = new PanelConfig(panelConfig);
  1164                 copiedList.add(panelConfig);
  1167             return copiedList;
  1170         private void setPanelIsDisabled(PanelConfig panelConfig, boolean disabled) {
  1171             if (panelConfig.isDisabled() == disabled) {
  1172                 return;
  1175             panelConfig.setIsDisabled(disabled);
  1176             mEnabledCount += (disabled ? -1 : 1);
  1179         /**
  1180          * Gets the ID of the current default panel.
  1181          */
  1182         public String getDefaultPanelId() {
  1183             ThreadUtils.assertOnThread(mOriginalThread);
  1185             if (mDefaultPanel == null) {
  1186                 return null;
  1189             return mDefaultPanel.getId();
  1192         /**
  1193          * Set a new default panel.
  1195          * @param panelId the ID of the new default panel.
  1196          */
  1197         public void setDefault(String panelId) {
  1198             ThreadUtils.assertOnThread(mOriginalThread);
  1200             final PanelConfig panelConfig = getPanelOrThrow(panelId);
  1201             if (isCurrentDefaultPanel(panelConfig)) {
  1202                 return;
  1205             if (mDefaultPanel != null) {
  1206                 mDefaultPanel.setIsDefault(false);
  1209             panelConfig.setIsDefault(true);
  1210             setPanelIsDisabled(panelConfig, false);
  1212             mDefaultPanel = panelConfig;
  1213             mHasChanged = true;
  1216         /**
  1217          * Toggles disabled state for a panel.
  1219          * @param panelId the ID of the target panel.
  1220          * @param disabled true to disable the panel.
  1221          */
  1222         public void setDisabled(String panelId, boolean disabled) {
  1223             ThreadUtils.assertOnThread(mOriginalThread);
  1225             final PanelConfig panelConfig = getPanelOrThrow(panelId);
  1226             if (panelConfig.isDisabled() == disabled) {
  1227                 return;
  1230             setPanelIsDisabled(panelConfig, disabled);
  1232             if (disabled) {
  1233                 if (isCurrentDefaultPanel(panelConfig)) {
  1234                     panelConfig.setIsDefault(false);
  1235                     findNewDefault();
  1237             } else if (mEnabledCount == 1) {
  1238                 setDefault(panelId);
  1241             mHasChanged = true;
  1244         /**
  1245          * Adds a new {@code PanelConfig}. It will do nothing if the
  1246          * {@code Editor} already contains a panel with the same ID.
  1248          * @param panelConfig the {@code PanelConfig} instance to be added.
  1249          * @return true if the item has been added.
  1250          */
  1251         public boolean install(PanelConfig panelConfig) {
  1252             ThreadUtils.assertOnThread(mOriginalThread);
  1254             if (panelConfig == null) {
  1255                 throw new IllegalStateException("Can't install a null panel");
  1258             if (!panelConfig.isDynamic()) {
  1259                 throw new IllegalStateException("Can't install a built-in panel: " + panelConfig.getId());
  1262             if (panelConfig.isDisabled()) {
  1263                 throw new IllegalStateException("Can't install a disabled panel: " + panelConfig.getId());
  1266             boolean installed = false;
  1268             final String id = panelConfig.getId();
  1269             if (!mConfigMap.containsKey(id)) {
  1270                 mConfigMap.put(id, panelConfig);
  1271                 mConfigOrder.add(id);
  1273                 mEnabledCount++;
  1274                 if (mEnabledCount == 1 || panelConfig.isDefault()) {
  1275                     setDefault(panelConfig.getId());
  1278                 installed = true;
  1280                 // Add an event to the queue if a new panel is sucessfully installed.
  1281                 mEventQueue.add(GeckoEvent.createBroadcastEvent("HomePanels:Installed", panelConfig.getId()));
  1284             mHasChanged = true;
  1285             return installed;
  1288         /**
  1289          * Removes an existing panel.
  1291          * @return true if the item has been removed.
  1292          */
  1293         public boolean uninstall(String panelId) {
  1294             ThreadUtils.assertOnThread(mOriginalThread);
  1296             final PanelConfig panelConfig = mConfigMap.get(panelId);
  1297             if (panelConfig == null) {
  1298                 return false;
  1301             if (!panelConfig.isDynamic()) {
  1302                 throw new IllegalStateException("Can't uninstall a built-in panel: " + panelConfig.getId());
  1305             mConfigMap.remove(panelId);
  1306             mConfigOrder.remove(panelId);
  1308             if (!panelConfig.isDisabled()) {
  1309                 mEnabledCount--;
  1312             if (isCurrentDefaultPanel(panelConfig)) {
  1313                 findNewDefault();
  1316             // Add an event to the queue if a panel is succesfully uninstalled.
  1317             mEventQueue.add(GeckoEvent.createBroadcastEvent("HomePanels:Uninstalled", panelId));
  1319             mHasChanged = true;
  1320             return true;
  1323         /**
  1324          * Moves panel associated with panelId to the specified position.
  1326          * @param panelId Id of panel
  1327          * @param destIndex Destination position
  1328          * @return true if move succeeded
  1329          */
  1330         public boolean moveTo(String panelId, int destIndex) {
  1331             ThreadUtils.assertOnThread(mOriginalThread);
  1333             if (!mConfigOrder.contains(panelId)) {
  1334                 return false;
  1337             mConfigOrder.remove(panelId);
  1338             mConfigOrder.add(destIndex, panelId);
  1339             mHasChanged = true;
  1341             return true;
  1344         /**
  1345          * Replaces an existing panel with a new {@code PanelConfig} instance.
  1347          * @return true if the item has been updated.
  1348          */
  1349         public boolean update(PanelConfig panelConfig) {
  1350             ThreadUtils.assertOnThread(mOriginalThread);
  1352             if (panelConfig == null) {
  1353                 throw new IllegalStateException("Can't update a null panel");
  1356             boolean updated = false;
  1358             final String id = panelConfig.getId();
  1359             if (mConfigMap.containsKey(id)) {
  1360                 final PanelConfig oldPanelConfig = mConfigMap.put(id, panelConfig);
  1362                 // The disabled and default states can't never be
  1363                 // changed by an update operation.
  1364                 panelConfig.setIsDefault(oldPanelConfig.isDefault());
  1365                 panelConfig.setIsDisabled(oldPanelConfig.isDisabled());
  1367                 updated = true;
  1370             mHasChanged = true;
  1371             return updated;
  1374         /**
  1375          * Saves the current {@code Editor} state asynchronously in the
  1376          * background thread.
  1378          * @return the resulting {@code State} instance.
  1379          */
  1380         public State apply() {
  1381             ThreadUtils.assertOnThread(mOriginalThread);
  1383             // We're about to save the current state in the background thread
  1384             // so we should use a deep copy of the PanelConfig instances to
  1385             // avoid saving corrupted state.
  1386             final State newConfigState =
  1387                     new State(mHomeConfig, makeOrderedCopy(true), isDefault());
  1389             // Copy the event queue to a new list, so that we only modify mEventQueue on
  1390             // the original thread where it was created.
  1391             final LinkedList<GeckoEvent> eventQueueCopy = new LinkedList<GeckoEvent>(mEventQueue);
  1392             mEventQueue.clear();
  1394             ThreadUtils.getBackgroundHandler().post(new Runnable() {
  1395                 @Override
  1396                 public void run() {
  1397                     mHomeConfig.save(newConfigState);
  1399                     // Send pending events after the new config is saved.
  1400                     sendEventsToGecko(eventQueueCopy);
  1402             });
  1404             return newConfigState;
  1407         /**
  1408          * Saves the current {@code Editor} state synchronously in the
  1409          * current thread.
  1411          * @return the resulting {@code State} instance.
  1412          */
  1413         public State commit() {
  1414             ThreadUtils.assertOnThread(mOriginalThread);
  1416             final State newConfigState =
  1417                     new State(mHomeConfig, makeOrderedCopy(false), isDefault());
  1419             // This is a synchronous blocking operation, hence no
  1420             // need to deep copy the current PanelConfig instances.
  1421             mHomeConfig.save(newConfigState);
  1423             // Send pending events after the new config is saved.
  1424             sendEventsToGecko(mEventQueue);
  1425             mEventQueue.clear();
  1427             return newConfigState;
  1430         /**
  1431          * Returns whether the {@code Editor} represents the default
  1432          * {@code HomeConfig} configuration without any unsaved changes.
  1433          */
  1434         public boolean isDefault() {
  1435             ThreadUtils.assertOnThread(mOriginalThread);
  1437             return (!mHasChanged && mIsFromDefault);
  1440         public boolean isEmpty() {
  1441             return mConfigMap.isEmpty();
  1444         private void sendEventsToGecko(List<GeckoEvent> events) {
  1445             for (GeckoEvent e : events) {
  1446                 GeckoAppShell.sendEventToGecko(e);
  1450         private class EditorIterator implements Iterator<PanelConfig> {
  1451             private final Iterator<String> mOrderIterator;
  1453             public EditorIterator() {
  1454                 mOrderIterator = mConfigOrder.iterator();
  1457             @Override
  1458             public boolean hasNext() {
  1459                 return mOrderIterator.hasNext();
  1462             @Override
  1463             public PanelConfig next() {
  1464                 final String panelId = mOrderIterator.next();
  1465                 return mConfigMap.get(panelId);
  1468             @Override
  1469             public void remove() {
  1470                 throw new UnsupportedOperationException("Can't 'remove' from on Editor iterator.");
  1474         @Override
  1475         public Iterator<PanelConfig> iterator() {
  1476             ThreadUtils.assertOnThread(mOriginalThread);
  1478             return new EditorIterator();
  1482     public interface OnReloadListener {
  1483         public void onReload();
  1486     public interface HomeConfigBackend {
  1487         public State load();
  1488         public void save(State configState);
  1489         public String getLocale();
  1490         public void setOnReloadListener(OnReloadListener listener);
  1493     // UUIDs used to create PanelConfigs for default built-in panels
  1494     private static final String TOP_SITES_PANEL_ID = "4becc86b-41eb-429a-a042-88fe8b5a094e";
  1495     private static final String BOOKMARKS_PANEL_ID = "7f6d419a-cd6c-4e34-b26f-f68b1b551907";
  1496     private static final String READING_LIST_PANEL_ID = "20f4549a-64ad-4c32-93e4-1dcef792733b";
  1497     private static final String HISTORY_PANEL_ID = "f134bf20-11f7-4867-ab8b-e8e705d7fbe8";
  1499     private final HomeConfigBackend mBackend;
  1501     public HomeConfig(HomeConfigBackend backend) {
  1502         mBackend = backend;
  1505     public State load() {
  1506         final State configState = mBackend.load();
  1507         configState.setHomeConfig(this);
  1509         return configState;
  1512     public String getLocale() {
  1513         return mBackend.getLocale();
  1516     public void save(State configState) {
  1517         mBackend.save(configState);
  1520     public void setOnReloadListener(OnReloadListener listener) {
  1521         mBackend.setOnReloadListener(listener);
  1524     public static PanelConfig createBuiltinPanelConfig(Context context, PanelType panelType) {
  1525         return createBuiltinPanelConfig(context, panelType, EnumSet.noneOf(PanelConfig.Flags.class));
  1528     public static PanelConfig createBuiltinPanelConfig(Context context, PanelType panelType, EnumSet<PanelConfig.Flags> flags) {
  1529         int titleId = 0;
  1530         String id = null;
  1532         switch(panelType) {
  1533             case TOP_SITES:
  1534                 titleId = R.string.home_top_sites_title;
  1535                 id = TOP_SITES_PANEL_ID;
  1536                 break;
  1538             case BOOKMARKS:
  1539                 titleId = R.string.bookmarks_title;
  1540                 id = BOOKMARKS_PANEL_ID;
  1541                 break;
  1543             case HISTORY:
  1544                 titleId = R.string.home_history_title;
  1545                 id = HISTORY_PANEL_ID;
  1546                 break;
  1548             case READING_LIST:
  1549                 titleId = R.string.reading_list_title;
  1550                 id = READING_LIST_PANEL_ID;
  1551                 break;
  1553             case DYNAMIC:
  1554                 throw new IllegalArgumentException("createBuiltinPanelConfig() is only for built-in panels");
  1557         return new PanelConfig(panelType, context.getString(titleId), id, flags);
  1560     public static HomeConfig getDefault(Context context) {
  1561         return new HomeConfig(new HomeConfigPrefsBackend(context));

mercurial