Home | History | Annotate | Download | only in dialog
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.settings.dialog;
     18 
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.Resources;
     22 import android.graphics.drawable.Drawable;
     23 import android.net.Uri;
     24 import android.os.Bundle;
     25 import android.os.Parcel;
     26 import android.os.Parcelable;
     27 import android.text.TextUtils;
     28 import android.util.Log;
     29 
     30 import java.util.ArrayList;
     31 
     32 /**
     33  * A data class which represents a settings layout within an
     34  * {@link SettingsLayoutFragment}. Represents a list of choices the
     35  * user can make, a radio-button list of configuration options, or just a
     36  * list of information.
     37  */
     38 public class Layout implements Parcelable {
     39 
     40     public interface LayoutNodeRefreshListener {
     41         void onRefreshView();
     42         Node getSelectedNode();
     43     }
     44 
     45     public interface ContentNodeRefreshListener {
     46         void onRefreshView();
     47     }
     48 
     49     public interface Node {
     50         String getTitle();
     51     }
     52 
     53     private abstract static class LayoutTreeNode implements Node {
     54         LayoutTreeBranch mParent;
     55 
     56         void Log(int level) {
     57         }
     58     }
     59 
     60     private abstract static class LayoutTreeBranch extends LayoutTreeNode {
     61         ArrayList<LayoutTreeNode> mChildren;
     62         LayoutTreeBranch() {
     63             mChildren = new ArrayList<LayoutTreeNode>();
     64         }
     65     }
     66 
     67     public static class LayoutRow {
     68         public static final int NO_CHECK_SET = 0;
     69         public static final int VIEW_TYPE_ACTION = 0;
     70         public static final int VIEW_TYPE_STATIC = 1;
     71 
     72         private String mTitle;
     73         private StringGetter mDescription;
     74         private LayoutTreeNode mNode;
     75         private boolean mEnabled;
     76         private int mViewType;
     77         private boolean mChecked = false;
     78         private Drawable mIcon = null;
     79 
     80         public Node getNode() {
     81             return mNode;
     82         }
     83 
     84         public Uri getIconUri() {
     85             return null;
     86         }
     87 
     88         public Drawable getIcon() {
     89             return mIcon;
     90         }
     91 
     92         public int getCheckSetId() {
     93             return 0;
     94         }
     95 
     96         public boolean isChecked() {
     97             return mChecked;
     98         }
     99 
    100         public void setChecked(boolean v) {
    101             mChecked = v;
    102         }
    103 
    104         public boolean infoOnly() {
    105             return false;
    106         }
    107 
    108         public boolean isEnabled() {
    109             return mEnabled;
    110         }
    111 
    112         public boolean hasNext() {
    113             return false;
    114         }
    115 
    116         public boolean hasMultilineDescription() {
    117             return false;
    118         }
    119 
    120         public String getTitle() {
    121             return mTitle;
    122         }
    123 
    124         public StringGetter getDescription() {
    125             return mDescription;
    126         }
    127 
    128         public int getViewType() {
    129             return mViewType;
    130         }
    131 
    132         public boolean isGoBack() {
    133             if (mNode instanceof Action) {
    134                 Action a = (Action) mNode;
    135                 if (a.mActionId == Action.ACTION_BACK) {
    136                     return true;
    137                 }
    138             }
    139             return false;
    140         }
    141 
    142         public Action getUserAction() {
    143             if (mNode instanceof Action) {
    144                 Action a = (Action) mNode;
    145                 if (a.mActionId != Action.ACTION_NONE) {
    146                     return a;
    147                 }
    148             }
    149             return null;
    150         }
    151 
    152         public int getContentIconRes() {
    153             if (mNode instanceof Header) {
    154                 return ((Header) mNode).mContentIconRes;
    155             }
    156             return 0;
    157         }
    158 
    159         public LayoutRow(LayoutTreeNode node) {
    160             mNode = node;
    161             mViewType = VIEW_TYPE_ACTION;
    162             Appearence a;
    163             if (node instanceof Header) {
    164                 a = ((Header) node).mAppearence;
    165                 mEnabled = true;
    166             } else if (node instanceof Action) {
    167                 a = ((Action) node).mAppearence;
    168                 mEnabled = true;
    169             } else if (node instanceof Status) {
    170                 a = ((Status) node).mAppearence;
    171                 mEnabled = true;
    172             } else {
    173                 a = null;
    174                 mEnabled = false;
    175                 if (node instanceof Static) {
    176                     mViewType = VIEW_TYPE_STATIC;
    177                     Static s = (Static) node;
    178                     mTitle = s.mTitle;
    179                 }
    180             }
    181             if (a != null) {
    182                 mTitle = a.getTitle();
    183                 mDescription = a.mDescriptionGetter;
    184                 mIcon = a.getIcon();
    185                 mChecked = a.isChecked();
    186             }
    187         }
    188     }
    189 
    190     public abstract static class DrawableGetter {
    191         public abstract Drawable get();
    192 
    193         /**
    194          * Notification from client that antecedent data has changed and the drawable should be
    195          * redisplayed.
    196          */
    197         public void refreshView() {
    198             //TODO - When implementing, ensure that multiple updates from the same event do not
    199             // cause multiple view updates.
    200         }
    201     }
    202 
    203     public abstract static class StringGetter {
    204         private ContentNodeRefreshListener mListener;
    205 
    206         public void setListener(ContentNodeRefreshListener listener) {
    207             mListener = listener;
    208         }
    209 
    210         public abstract String get();
    211 
    212         /**
    213          * Notification from client that antecedent data has changed and the string should be
    214          * redisplayed.
    215          */
    216         public void refreshView() {
    217             if (mListener != null) {
    218                 mListener.onRefreshView();
    219             }
    220         }
    221     }
    222 
    223     /**
    224      * Implementation of "StringGetter" that stores and returns a literal string.
    225      */
    226     private static class LiteralStringGetter extends StringGetter {
    227         private final String mValue;
    228         public String get() {
    229             return mValue;
    230         }
    231         LiteralStringGetter(String value) {
    232             mValue = value;
    233         }
    234     }
    235 
    236     /**
    237      * Implementation of "StringGetter" that stores a string resource id and returns a string.
    238      */
    239     private static class ResourceStringGetter extends StringGetter {
    240         private final int mStringResourceId;
    241         private final Resources mRes;
    242         public String get() {
    243             return mRes.getString(mStringResourceId);
    244         }
    245         ResourceStringGetter(Resources res, int stringResourceId) {
    246             mRes = res;
    247             mStringResourceId = stringResourceId;
    248         }
    249     }
    250 
    251     public abstract static class LayoutGetter extends LayoutTreeNode {
    252         // Layout manages this listener; removing it when this node is not visible and setting it
    253         // when it is.  Users are expected to set the listener with Layout.setRefreshViewListener.
    254         private LayoutNodeRefreshListener mListener;
    255 
    256         public void setListener(LayoutNodeRefreshListener listener) {
    257             mListener = listener;
    258         }
    259 
    260         public void notVisible() {
    261             mListener = null;
    262         }
    263 
    264         public abstract Layout get();
    265 
    266         public Node getSelectedNode() {
    267             if (mListener != null) {
    268                 return mListener.getSelectedNode();
    269             } else {
    270                 return null;
    271             }
    272         }
    273 
    274         /**
    275          * Notification from client that antecedent data has changed and the list containing the
    276          * contents of this getter should be updated.
    277          */
    278         public void refreshView() {
    279             if (mListener != null) {
    280                 mListener.onRefreshView();
    281             }
    282         }
    283 
    284         @Override
    285         public String getTitle() {
    286             return null;
    287         }
    288 
    289         void Log(int level) {
    290             Log.d("Layout", indent(level) + "LayoutGetter");
    291             Layout l = get();
    292             l.Log(level + 1);
    293         }
    294     }
    295 
    296     private static class Appearence {
    297         private Drawable mIcon;
    298         private DrawableGetter mIconGetter;
    299         private String mTitle;
    300         private StringGetter mDescriptionGetter;
    301         private boolean mChecked = false;
    302 
    303         public String toString() {
    304             StringBuilder stringBuilder = new StringBuilder()
    305                 .append("'")
    306                 .append(mTitle)
    307                 .append("'");
    308             if (mDescriptionGetter != null) {
    309                 stringBuilder
    310                     .append(" : '")
    311                     .append(mDescriptionGetter.get())
    312                     .append("'");
    313             }
    314             stringBuilder
    315                 .append(" : '")
    316                 .append(mChecked)
    317                 .append("'");
    318             return stringBuilder.toString();
    319         }
    320 
    321         public String getTitle() {
    322             return mTitle;
    323         }
    324 
    325         public Drawable getIcon() {
    326             if (mIconGetter != null) {
    327                 return mIconGetter.get();
    328             } else {
    329                 return mIcon;
    330             }
    331         }
    332 
    333         public boolean isChecked() {
    334             return mChecked;
    335         }
    336     }
    337 
    338     /**
    339      * Header is a container for a sub-menu of "LayoutTreeNode" items.
    340      */
    341     public static class Header extends LayoutTreeBranch {
    342         private Appearence mAppearence = new Appearence();
    343         private int mSelectedIndex = 0;
    344         private String mDetailedDescription;
    345         private int mContentIconRes = 0;
    346 
    347         public static class Builder {
    348             private Resources mRes;
    349             private Header mHeader = new Header();
    350 
    351             public Builder(Resources res) {
    352                 mRes = res;
    353             }
    354 
    355             public Builder icon(int resId) {
    356                 mHeader.mAppearence.mIcon = mRes.getDrawable(resId);
    357                 return this;
    358             }
    359 
    360             public Builder icon(DrawableGetter drawableGetter) {
    361                 mHeader.mAppearence.mIconGetter = drawableGetter;
    362                 return this;
    363             }
    364 
    365             public Builder contentIconRes(int resId) {
    366                 mHeader.mContentIconRes = resId;
    367                 return this;
    368             }
    369 
    370             public Builder title(int resId) {
    371                 mHeader.mAppearence.mTitle = mRes.getString(resId);
    372                 return this;
    373             }
    374 
    375             public Builder description(int resId) {
    376                 mHeader.mAppearence.mDescriptionGetter = new ResourceStringGetter(mRes, resId);
    377                 return this;
    378             }
    379 
    380             public Builder title(String title) {
    381                 mHeader.mAppearence.mTitle = title;
    382                 return this;
    383             }
    384 
    385             public Builder description(String description) {
    386                 mHeader.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
    387                 return this;
    388             }
    389 
    390             public Builder description(StringGetter description) {
    391                 mHeader.mAppearence.mDescriptionGetter = description;
    392                 return this;
    393             }
    394 
    395             public Builder detailedDescription(int resId) {
    396                 mHeader.mDetailedDescription = mRes.getString(resId);
    397                 return this;
    398             }
    399 
    400             public Builder detailedDescription(String detailedDescription) {
    401                 mHeader.mDetailedDescription = detailedDescription;
    402                 return this;
    403             }
    404 
    405             public Header build() {
    406                 return mHeader;
    407             }
    408         }
    409 
    410         @Override
    411         public String getTitle() {
    412             return mAppearence.getTitle();
    413         }
    414 
    415         public Header add(LayoutTreeNode node) {
    416             node.mParent = this;
    417             mChildren.add(node);
    418             return this;
    419         }
    420 
    421         String getDetailedDescription() {
    422             return mDetailedDescription;
    423         }
    424 
    425         void Log(int level) {
    426             Log.d("Layout", indent(level) + "Header  " + mAppearence);
    427             for (LayoutTreeNode i : mChildren)
    428                 i.Log(level + 1);
    429         }
    430     }
    431 
    432     public static class Action extends LayoutTreeNode {
    433         public static final int ACTION_NONE = -1;
    434         public static final int ACTION_INTENT = -2;
    435         public static final int ACTION_BACK = -3;
    436         private int mActionId;
    437         private Intent mIntent;
    438         private Appearence mAppearence = new Appearence();
    439         private Bundle mActionData;
    440         private boolean mDefaultSelection = false;
    441 
    442         private Action(int id) {
    443             mActionId = id;
    444         }
    445 
    446         private Action(Intent intent) {
    447             mActionId = ACTION_INTENT;
    448             mIntent = intent;
    449         }
    450 
    451         public static class Builder {
    452             private Resources mRes;
    453             private Action mAction;
    454 
    455             public Builder(Resources res, int id) {
    456                 mRes = res;
    457                 mAction = new Action(id);
    458             }
    459 
    460             public Builder(Resources res, Intent intent) {
    461                 mRes = res;
    462                 mAction = new Action(intent);
    463             }
    464 
    465             public Builder title(int resId) {
    466                 mAction.mAppearence.mTitle = mRes.getString(resId);
    467                 return this;
    468             }
    469 
    470             public Builder description(int resId) {
    471                 mAction.mAppearence.mDescriptionGetter = new LiteralStringGetter(mRes.getString(
    472                         resId));
    473                 return this;
    474             }
    475 
    476             public Builder title(String title) {
    477                 mAction.mAppearence.mTitle = title;
    478                 return this;
    479             }
    480 
    481              public Builder icon(int resId) {
    482                  mAction.mAppearence.mIcon = mRes.getDrawable(resId);
    483                  return this;
    484              }
    485 
    486             public Builder description(String description) {
    487                 mAction.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
    488                 return this;
    489             }
    490 
    491             public Builder description(StringGetter description) {
    492                 mAction.mAppearence.mDescriptionGetter = description;
    493                 return this;
    494             }
    495 
    496             public Builder checked(boolean checked) {
    497                 mAction.mAppearence.mChecked = checked;
    498                 return this;
    499             }
    500 
    501             public Builder data(Bundle data) {
    502                 mAction.mActionData = data;
    503                 return this;
    504             }
    505 
    506             /*
    507              * Makes this action default initial selection when the list is displayed.
    508              */
    509             public Builder defaultSelection() {
    510                 mAction.mDefaultSelection = true;
    511                 return this;
    512             }
    513 
    514             public Action build() {
    515                 return mAction;
    516             }
    517         }
    518 
    519         void Log(int level) {
    520             Log.d("Layout", indent(level) + "Action  #" + mActionId + "  " + mAppearence);
    521         }
    522 
    523         public int getId() {
    524             return mActionId;
    525         }
    526 
    527         public Intent getIntent() {
    528             return mIntent;
    529         }
    530 
    531         @Override
    532         public String getTitle() {
    533             return mAppearence.getTitle();
    534         }
    535 
    536         public Bundle getData() {
    537             return mActionData;
    538         }
    539     }
    540 
    541     public static class Status extends LayoutTreeNode {
    542         private Appearence mAppearence = new Appearence();
    543 
    544         public static class Builder {
    545             private Resources mRes;
    546             private Status mStatus = new Status();
    547 
    548             public Builder(Resources res) {
    549                 mRes = res;
    550             }
    551 
    552             public Builder icon(int resId) {
    553                 mStatus.mAppearence.mIcon = mRes.getDrawable(resId);
    554                 return this;
    555             }
    556 
    557             public Builder title(int resId) {
    558                 mStatus.mAppearence.mTitle = mRes.getString(resId);
    559                 return this;
    560             }
    561 
    562             public Builder description(int resId) {
    563                 mStatus.mAppearence.mDescriptionGetter = new LiteralStringGetter(mRes.getString(
    564                         resId));
    565                 return this;
    566             }
    567 
    568             public Builder title(String title) {
    569                 mStatus.mAppearence.mTitle = title;
    570                 return this;
    571             }
    572 
    573             public Builder description(String description) {
    574                 mStatus.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
    575                 return this;
    576             }
    577 
    578             public Builder description(StringGetter description) {
    579                 mStatus.mAppearence.mDescriptionGetter = description;
    580                 return this;
    581             }
    582 
    583             public Status build() {
    584                 return mStatus;
    585             }
    586         }
    587 
    588         @Override
    589         public String getTitle() {
    590             return mAppearence.getTitle();
    591         }
    592 
    593         void Log(int level) {
    594             Log.d("Layout", indent(level) + "Status  " + mAppearence);
    595         }
    596     }
    597 
    598     public static class Static extends LayoutTreeNode {
    599         private String mTitle;
    600 
    601         public static class Builder {
    602             private Resources mRes;
    603             private Static mStatic = new Static();
    604 
    605             public Builder(Resources res) {
    606                 mRes = res;
    607             }
    608 
    609             public Builder title(int resId) {
    610                 mStatic.mTitle = mRes.getString(resId);
    611                 return this;
    612             }
    613 
    614             public Builder title(String title) {
    615                 mStatic.mTitle = title;
    616                 return this;
    617             }
    618 
    619             public Static build() {
    620                 return mStatic;
    621             }
    622         }
    623 
    624         @Override
    625         public String getTitle() {
    626             return mTitle;
    627         }
    628 
    629         void Log(int level) {
    630             Log.d("Layout", indent(level) + "Static  '" + mTitle + "'");
    631         }
    632     }
    633 
    634     /**
    635      * Pointer to currently visible item.
    636      */
    637     private Header mNavigationCursor;
    638 
    639     /**
    640      * Index of selected item when items are displayed. This is used by LayoutGetter to implemented
    641      * selection stability, where a LayoutGetter can arrange for a list that is refreshed regularly
    642      * to carry forward a selection.
    643      */
    644     private int mInitialItemIndex = -1;
    645     private final ArrayList<LayoutRow> mLayoutRows = new ArrayList<LayoutRow>();
    646     private final ArrayList<LayoutGetter> mVisibleLayoutGetters = new ArrayList<LayoutGetter>();
    647     private final ArrayList<LayoutTreeNode> mChildren = new ArrayList<LayoutTreeNode>();
    648     private String mTopLevelBreadcrumb = "";
    649     private LayoutNodeRefreshListener mListener;
    650 
    651     public ArrayList<LayoutRow> getLayoutRows() {
    652         return mLayoutRows;
    653     }
    654 
    655     public void setRefreshViewListener(LayoutNodeRefreshListener listener) {
    656         mListener = listener;
    657     }
    658 
    659     /**
    660      * Return the breadcrumb the user should see in the content pane.
    661      */
    662     public String getBreadcrumb() {
    663       if (mNavigationCursor.mParent == null) {
    664           // At the top level of the layout.
    665           return mTopLevelBreadcrumb;
    666       } else {
    667           // Showing a header down the hierarchy, breadcrumb is title of item above.
    668           return ((Header) (mNavigationCursor.mParent)).mAppearence.mTitle;
    669       }
    670     }
    671 
    672     /**
    673      * Navigate up one level, return true if a parent node is now visible. Return false if the
    674      * already at the top level node. The controlling fragment interprets a false return value as
    675      * "stop activity".
    676      */
    677     public boolean goBack() {
    678         if (mNavigationCursor.mParent != null) {
    679             Header u = (Header) mNavigationCursor.mParent;
    680             if (u != null) {
    681                 mNavigationCursor = u;
    682                 updateLayoutRows();
    683                 return true;
    684             }
    685         }
    686         return false;
    687     }
    688 
    689     /**
    690      * Parcelable implementation.
    691      */
    692     public Layout(Parcel in) {
    693     }
    694 
    695     public Layout() {
    696         mNavigationCursor = null;
    697     }
    698 
    699     @Override
    700     public int describeContents() {
    701         return 0;
    702     }
    703 
    704     @Override
    705     public void writeToParcel(Parcel out, int flags) {
    706     }
    707 
    708     public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
    709         public Layout createFromParcel(Parcel in) {
    710             return new Layout(in);
    711         }
    712 
    713         public Layout[] newArray(int size) {
    714             return new Layout[size];
    715         }
    716     };
    717 
    718     String getTitle() {
    719         return mNavigationCursor.mAppearence.mTitle;
    720     }
    721 
    722     Drawable getIcon() {
    723         return mNavigationCursor.mAppearence.getIcon();
    724     }
    725 
    726     String getDescription() {
    727         return mNavigationCursor.getDetailedDescription();
    728     }
    729 
    730     public void goToTitle(String title) {
    731         while (mNavigationCursor.mParent != null) {
    732             mNavigationCursor = (Header) (mNavigationCursor.mParent);
    733             if (TextUtils.equals(mNavigationCursor.mAppearence.mTitle, title)) {
    734                 break;
    735             }
    736         }
    737         updateLayoutRows();
    738     }
    739 
    740     /*
    741      * Respond to a user click on "layoutRow" and return "true" if the state of the display has
    742      * changed. A controlling fragment will respond to a "true" return by updating the view.
    743      */
    744     public boolean onClickNavigate(LayoutRow layoutRow) {
    745         LayoutTreeNode node = layoutRow.mNode;
    746         if (node instanceof Header) {
    747             mNavigationCursor.mSelectedIndex = mLayoutRows.indexOf(layoutRow);
    748             mNavigationCursor = (Header) node;
    749             updateLayoutRows();
    750             return true;
    751         }
    752         return false;
    753     }
    754 
    755     public void reloadLayoutRows() {
    756         updateLayoutRows();
    757     }
    758 
    759     public Layout add(Header header) {
    760         header.mParent = null;
    761         mChildren.add(header);
    762         return this;
    763     }
    764 
    765     public Layout add(LayoutTreeNode leaf) {
    766         leaf.mParent = null;
    767         mChildren.add(leaf);
    768         return this;
    769     }
    770 
    771     public Layout breadcrumb(String topLevelBreadcrumb) {
    772         mTopLevelBreadcrumb = topLevelBreadcrumb;
    773         return this;
    774     }
    775 
    776     /**
    777      * Sets the selected node to the first top level node with its title member equal to "title". If
    778      * "title" is null, empty, or there are no top level nodes with a title member equal to "title",
    779      * set the first node in the list as the selected.
    780      */
    781     public Layout setSelectedByTitle(String title) {
    782         for (int i = 0; i < mChildren.size(); ++i) {
    783             if (TextUtils.equals(mChildren.get(i).getTitle(), title)) {
    784                 mInitialItemIndex = i;
    785                 break;
    786             }
    787         }
    788         return this;
    789     }
    790 
    791     public void Log(int level) {
    792         for (LayoutTreeNode i : mChildren) {
    793             i.Log(level + 1);
    794         }
    795     }
    796 
    797     public void Log() {
    798         Log.d("Layout", "----- Layout");
    799         Log(0);
    800     }
    801 
    802     public void navigateToRoot() {
    803         if (mChildren.size() > 0) {
    804             mNavigationCursor = (Header) mChildren.get(0);
    805         } else {
    806             mNavigationCursor = null;
    807         }
    808         updateLayoutRows();
    809     }
    810 
    811     public int getSelectedIndex() {
    812         return mNavigationCursor.mSelectedIndex;
    813     }
    814 
    815     public void setSelectedIndex(int index) {
    816         mNavigationCursor.mSelectedIndex = index;
    817     }
    818 
    819     public void setParentSelectedIndex(int index) {
    820         if (mNavigationCursor.mParent != null) {
    821             Header u = (Header) mNavigationCursor.mParent;
    822             u.mSelectedIndex = index;
    823         }
    824     }
    825 
    826     private void addNodeListToLayoutRows(ArrayList<LayoutTreeNode> list) {
    827         for (LayoutTreeNode node : list) {
    828             if (node instanceof LayoutGetter) {
    829                 // Add subitems of "node" recursively.
    830                 LayoutGetter layoutGetter = (LayoutGetter) node;
    831                 layoutGetter.setListener(mListener);
    832                 mVisibleLayoutGetters.add(layoutGetter);
    833                 Layout layout = layoutGetter.get();
    834                 for (LayoutTreeNode child : layout.mChildren) {
    835                     child.mParent = mNavigationCursor;
    836                 }
    837                 int initialIndex = layout.mInitialItemIndex;
    838                 if (initialIndex != -1) {
    839                     mNavigationCursor.mSelectedIndex = mLayoutRows.size() + initialIndex;
    840                 }
    841                 addNodeListToLayoutRows(layout.mChildren);
    842             } else {
    843                 if (node instanceof Action && ((Action) node).mDefaultSelection) {
    844                     mNavigationCursor.mSelectedIndex = mLayoutRows.size();
    845                 }
    846                 mLayoutRows.add(new LayoutRow(node));
    847             }
    848         }
    849     }
    850 
    851     private void updateLayoutRows() {
    852         mLayoutRows.clear();
    853         for (LayoutGetter layoutGetter : mVisibleLayoutGetters) {
    854             layoutGetter.notVisible();
    855         }
    856         mVisibleLayoutGetters.clear();
    857         addNodeListToLayoutRows(mNavigationCursor.mChildren);
    858     }
    859 
    860     private static String indent(int level) {
    861         String s = new String();
    862         for (int i = 0; i < level; ++i) {
    863             s += "  ";
    864         }
    865         return s;
    866     }
    867 }
    868