• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
onRefreshView()41         void onRefreshView();
getSelectedNode()42         Node getSelectedNode();
43     }
44 
45     public interface ContentNodeRefreshListener {
onRefreshView()46         void onRefreshView();
47     }
48 
49     public interface Node {
getTitle()50         String getTitle();
51     }
52 
53     private abstract static class LayoutTreeNode implements Node {
54         LayoutTreeBranch mParent;
55 
Log(int level)56         void Log(int level) {
57         }
58     }
59 
60     private abstract static class LayoutTreeBranch extends LayoutTreeNode {
61         ArrayList<LayoutTreeNode> mChildren;
LayoutTreeBranch()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 
getNode()80         public Node getNode() {
81             return mNode;
82         }
83 
getIconUri()84         public Uri getIconUri() {
85             return null;
86         }
87 
getIcon()88         public Drawable getIcon() {
89             return mIcon;
90         }
91 
getCheckSetId()92         public int getCheckSetId() {
93             return 0;
94         }
95 
isChecked()96         public boolean isChecked() {
97             return mChecked;
98         }
99 
setChecked(boolean v)100         public void setChecked(boolean v) {
101             mChecked = v;
102         }
103 
infoOnly()104         public boolean infoOnly() {
105             return false;
106         }
107 
isEnabled()108         public boolean isEnabled() {
109             return mEnabled;
110         }
111 
hasNext()112         public boolean hasNext() {
113             return false;
114         }
115 
hasMultilineDescription()116         public boolean hasMultilineDescription() {
117             return false;
118         }
119 
getTitle()120         public String getTitle() {
121             return mTitle;
122         }
123 
getDescription()124         public StringGetter getDescription() {
125             return mDescription;
126         }
127 
getViewType()128         public int getViewType() {
129             return mViewType;
130         }
131 
isGoBack()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 
getUserAction()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 
getContentIconRes()152         public int getContentIconRes() {
153             if (mNode instanceof Header) {
154                 return ((Header) mNode).mContentIconRes;
155             }
156             return 0;
157         }
158 
LayoutRow(LayoutTreeNode node)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 {
get()191         public abstract Drawable get();
192 
193         /**
194          * Notification from client that antecedent data has changed and the drawable should be
195          * redisplayed.
196          */
refreshView()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 
setListener(ContentNodeRefreshListener listener)206         public void setListener(ContentNodeRefreshListener listener) {
207             mListener = listener;
208         }
209 
get()210         public abstract String get();
211 
212         /**
213          * Notification from client that antecedent data has changed and the string should be
214          * redisplayed.
215          */
refreshView()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;
get()228         public String get() {
229             return mValue;
230         }
LiteralStringGetter(String value)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;
get()242         public String get() {
243             return mRes.getString(mStringResourceId);
244         }
ResourceStringGetter(Resources res, int stringResourceId)245         ResourceStringGetter(Resources res, int stringResourceId) {
246             mRes = res;
247             mStringResourceId = stringResourceId;
248         }
249     }
250 
251     public abstract static class LayoutGetter extends LayoutTreeNode {
252         private LayoutNodeRefreshListener mListener;
253 
setListener(LayoutNodeRefreshListener listener)254         public void setListener(LayoutNodeRefreshListener listener) {
255             mListener = listener;
256         }
257 
notVisible()258         public void notVisible() {
259             mListener = null;
260             onMovedOffScreen();
261         }
262 
get()263         public abstract Layout get();
264 
getSelectedNode()265         public Node getSelectedNode() {
266             if (mListener != null) {
267                 return mListener.getSelectedNode();
268             } else {
269                 return null;
270             }
271         }
272 
273         /**
274          * Notification to client that the list containting the contents of this getter is no longer
275          * visible and background tasks to update the getter contents should be stopped until the
276          * next "get()" call.
277          */
onMovedOffScreen()278         public void onMovedOffScreen() {
279         }
280 
281         /**
282          * Notification from client that antecedent data has changed and the list containing the
283          * contents of this getter should be updated.
284          */
refreshView()285         public void refreshView() {
286             if (mListener != null) {
287                 mListener.onRefreshView();
288             }
289         }
290 
291         @Override
getTitle()292         public String getTitle() {
293             return null;
294         }
295 
Log(int level)296         void Log(int level) {
297             Log.d("Layout", indent(level) + "LayoutGetter");
298             Layout l = get();
299             l.Log(level + 1);
300         }
301     }
302 
303     private static class Appearence {
304         private Drawable mIcon;
305         private DrawableGetter mIconGetter;
306         private String mTitle;
307         private StringGetter mDescriptionGetter;
308         private boolean mChecked = false;
309 
toString()310         public String toString() {
311             StringBuilder stringBuilder = new StringBuilder()
312                 .append("'")
313                 .append(mTitle)
314                 .append("'");
315             if (mDescriptionGetter != null) {
316                 stringBuilder
317                     .append(" : '")
318                     .append(mDescriptionGetter.get())
319                     .append("'");
320             }
321             stringBuilder
322                 .append(" : '")
323                 .append(mChecked)
324                 .append("'");
325             return stringBuilder.toString();
326         }
327 
getTitle()328         public String getTitle() {
329             return mTitle;
330         }
331 
getIcon()332         public Drawable getIcon() {
333             if (mIconGetter != null) {
334                 return mIconGetter.get();
335             } else {
336                 return mIcon;
337             }
338         }
339 
isChecked()340         public boolean isChecked() {
341             return mChecked;
342         }
343     }
344 
345     /**
346      * Header is a container for a sub-menu of "LayoutTreeNode" items.
347      */
348     public static class Header extends LayoutTreeBranch {
349         private Appearence mAppearence = new Appearence();
350         private int mSelectedIndex = 0;
351         private String mDetailedDescription;
352         private int mContentIconRes = 0;
353 
354         public static class Builder {
355             private Resources mRes;
356             private Header mHeader = new Header();
357 
Builder(Resources res)358             public Builder(Resources res) {
359                 mRes = res;
360             }
361 
icon(int resId)362             public Builder icon(int resId) {
363                 mHeader.mAppearence.mIcon = mRes.getDrawable(resId);
364                 return this;
365             }
366 
icon(DrawableGetter drawableGetter)367             public Builder icon(DrawableGetter drawableGetter) {
368                 mHeader.mAppearence.mIconGetter = drawableGetter;
369                 return this;
370             }
371 
contentIconRes(int resId)372             public Builder contentIconRes(int resId) {
373                 mHeader.mContentIconRes = resId;
374                 return this;
375             }
376 
title(int resId)377             public Builder title(int resId) {
378                 mHeader.mAppearence.mTitle = mRes.getString(resId);
379                 return this;
380             }
381 
description(int resId)382             public Builder description(int resId) {
383                 mHeader.mAppearence.mDescriptionGetter = new ResourceStringGetter(mRes, resId);
384                 return this;
385             }
386 
title(String title)387             public Builder title(String title) {
388                 mHeader.mAppearence.mTitle = title;
389                 return this;
390             }
391 
description(String description)392             public Builder description(String description) {
393                 mHeader.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
394                 return this;
395             }
396 
description(StringGetter description)397             public Builder description(StringGetter description) {
398                 mHeader.mAppearence.mDescriptionGetter = description;
399                 return this;
400             }
401 
detailedDescription(int resId)402             public Builder detailedDescription(int resId) {
403                 mHeader.mDetailedDescription = mRes.getString(resId);
404                 return this;
405             }
406 
detailedDescription(String detailedDescription)407             public Builder detailedDescription(String detailedDescription) {
408                 mHeader.mDetailedDescription = detailedDescription;
409                 return this;
410             }
411 
build()412             public Header build() {
413                 return mHeader;
414             }
415         }
416 
417         @Override
getTitle()418         public String getTitle() {
419             return mAppearence.getTitle();
420         }
421 
add(LayoutTreeNode node)422         public Header add(LayoutTreeNode node) {
423             node.mParent = this;
424             mChildren.add(node);
425             return this;
426         }
427 
getDetailedDescription()428         String getDetailedDescription() {
429             return mDetailedDescription;
430         }
431 
Log(int level)432         void Log(int level) {
433             Log.d("Layout", indent(level) + "Header  " + mAppearence);
434             for (LayoutTreeNode i : mChildren)
435                 i.Log(level + 1);
436         }
437     }
438 
439     public static class Action extends LayoutTreeNode {
440         public static final int ACTION_NONE = -1;
441         public static final int ACTION_INTENT = -2;
442         public static final int ACTION_BACK = -3;
443         private int mActionId;
444         private Intent mIntent;
445         private Appearence mAppearence = new Appearence();
446         private Bundle mActionData;
447         private boolean mDefaultSelection = false;
448 
Action(int id)449         private Action(int id) {
450             mActionId = id;
451         }
452 
Action(Intent intent)453         private Action(Intent intent) {
454             mActionId = ACTION_INTENT;
455             mIntent = intent;
456         }
457 
458         public static class Builder {
459             private Resources mRes;
460             private Action mAction;
461 
Builder(Resources res, int id)462             public Builder(Resources res, int id) {
463                 mRes = res;
464                 mAction = new Action(id);
465             }
466 
Builder(Resources res, Intent intent)467             public Builder(Resources res, Intent intent) {
468                 mRes = res;
469                 mAction = new Action(intent);
470             }
471 
title(int resId)472             public Builder title(int resId) {
473                 mAction.mAppearence.mTitle = mRes.getString(resId);
474                 return this;
475             }
476 
description(int resId)477             public Builder description(int resId) {
478                 mAction.mAppearence.mDescriptionGetter = new LiteralStringGetter(mRes.getString(
479                         resId));
480                 return this;
481             }
482 
title(String title)483             public Builder title(String title) {
484                 mAction.mAppearence.mTitle = title;
485                 return this;
486             }
487 
description(String description)488             public Builder description(String description) {
489                 mAction.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
490                 return this;
491             }
492 
checked(boolean checked)493             public Builder checked(boolean checked) {
494                 mAction.mAppearence.mChecked = checked;
495                 return this;
496             }
497 
data(Bundle data)498             public Builder data(Bundle data) {
499                 mAction.mActionData = data;
500                 return this;
501             }
502 
503             /*
504              * Makes this action default initial selection when the list is displayed.
505              */
defaultSelection()506             public Builder defaultSelection() {
507                 mAction.mDefaultSelection = true;
508                 return this;
509             }
510 
build()511             public Action build() {
512                 return mAction;
513             }
514         }
515 
Log(int level)516         void Log(int level) {
517             Log.d("Layout", indent(level) + "Action  #" + mActionId + "  " + mAppearence);
518         }
519 
getId()520         public int getId() {
521             return mActionId;
522         }
523 
getIntent()524         public Intent getIntent() {
525             return mIntent;
526         }
527 
528         @Override
getTitle()529         public String getTitle() {
530             return mAppearence.getTitle();
531         }
532 
getData()533         public Bundle getData() {
534             return mActionData;
535         }
536     }
537 
538     public static class Status extends LayoutTreeNode {
539         private Appearence mAppearence = new Appearence();
540 
541         public static class Builder {
542             private Resources mRes;
543             private Status mStatus = new Status();
544 
Builder(Resources res)545             public Builder(Resources res) {
546                 mRes = res;
547             }
548 
icon(int resId)549             public Builder icon(int resId) {
550                 mStatus.mAppearence.mIcon = mRes.getDrawable(resId);
551                 return this;
552             }
553 
title(int resId)554             public Builder title(int resId) {
555                 mStatus.mAppearence.mTitle = mRes.getString(resId);
556                 return this;
557             }
558 
description(int resId)559             public Builder description(int resId) {
560                 mStatus.mAppearence.mDescriptionGetter = new LiteralStringGetter(mRes.getString(
561                         resId));
562                 return this;
563             }
564 
title(String title)565             public Builder title(String title) {
566                 mStatus.mAppearence.mTitle = title;
567                 return this;
568             }
569 
description(String description)570             public Builder description(String description) {
571                 mStatus.mAppearence.mDescriptionGetter = new LiteralStringGetter(description);
572                 return this;
573             }
574 
description(StringGetter description)575             public Builder description(StringGetter description) {
576                 mStatus.mAppearence.mDescriptionGetter = description;
577                 return this;
578             }
579 
build()580             public Status build() {
581                 return mStatus;
582             }
583         }
584 
585         @Override
getTitle()586         public String getTitle() {
587             return mAppearence.getTitle();
588         }
589 
Log(int level)590         void Log(int level) {
591             Log.d("Layout", indent(level) + "Status  " + mAppearence);
592         }
593     }
594 
595     public static class Static extends LayoutTreeNode {
596         private String mTitle;
597 
598         public static class Builder {
599             private Resources mRes;
600             private Static mStatic = new Static();
601 
Builder(Resources res)602             public Builder(Resources res) {
603                 mRes = res;
604             }
605 
title(int resId)606             public Builder title(int resId) {
607                 mStatic.mTitle = mRes.getString(resId);
608                 return this;
609             }
610 
title(String title)611             public Builder title(String title) {
612                 mStatic.mTitle = title;
613                 return this;
614             }
615 
build()616             public Static build() {
617                 return mStatic;
618             }
619         }
620 
621         @Override
getTitle()622         public String getTitle() {
623             return mTitle;
624         }
625 
Log(int level)626         void Log(int level) {
627             Log.d("Layout", indent(level) + "Static  '" + mTitle + "'");
628         }
629     }
630 
631     /**
632      * Pointer to currently visible item.
633      */
634     private Header mNavigationCursor;
635 
636     /**
637      * Index of selected item when items are displayed. This is used by LayoutGetter to implemented
638      * selection stability, where a LayoutGetter can arrange for a list that is refreshed regularly
639      * to carry forward a selection.
640      */
641     private int mInitialItemIndex = -1;
642     private final ArrayList<LayoutRow> mLayoutRows = new ArrayList<LayoutRow>();
643     private final ArrayList<LayoutGetter> mVisibleLayoutGetters = new ArrayList<LayoutGetter>();
644     private final ArrayList<LayoutTreeNode> mChildren = new ArrayList<LayoutTreeNode>();
645     private String mTopLevelBreadcrumb = "";
646     private LayoutNodeRefreshListener mListener;
647 
getLayoutRows()648     public ArrayList<LayoutRow> getLayoutRows() {
649         return mLayoutRows;
650     }
651 
setRefreshViewListener(LayoutNodeRefreshListener listener)652     public void setRefreshViewListener(LayoutNodeRefreshListener listener) {
653         mListener = listener;
654     }
655 
656     /**
657      * Return the breadcrumb the user should see in the content pane.
658      */
getBreadcrumb()659     public String getBreadcrumb() {
660       if (mNavigationCursor.mParent == null) {
661           // At the top level of the layout.
662           return mTopLevelBreadcrumb;
663       } else {
664           // Showing a header down the hierarchy, breadcrumb is title of item above.
665           return ((Header) (mNavigationCursor.mParent)).mAppearence.mTitle;
666       }
667     }
668 
669     /**
670      * Navigate up one level, return true if a parent node is now visible. Return false if the
671      * already at the top level node. The controlling fragment interprets a false return value as
672      * "stop activity".
673      */
goBack()674     public boolean goBack() {
675         if (mNavigationCursor.mParent != null) {
676             Header u = (Header) mNavigationCursor.mParent;
677             if (u != null) {
678                 mNavigationCursor = u;
679                 updateLayoutRows();
680                 return true;
681             }
682         }
683         return false;
684     }
685 
686     /**
687      * Parcelable implementation.
688      */
Layout(Parcel in)689     public Layout(Parcel in) {
690     }
691 
Layout()692     public Layout() {
693         mNavigationCursor = null;
694     }
695 
696     @Override
describeContents()697     public int describeContents() {
698         return 0;
699     }
700 
701     @Override
writeToParcel(Parcel out, int flags)702     public void writeToParcel(Parcel out, int flags) {
703     }
704 
705     public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
706         public Layout createFromParcel(Parcel in) {
707             return new Layout(in);
708         }
709 
710         public Layout[] newArray(int size) {
711             return new Layout[size];
712         }
713     };
714 
getTitle()715     String getTitle() {
716         return mNavigationCursor.mAppearence.mTitle;
717     }
718 
getIcon()719     Drawable getIcon() {
720         return mNavigationCursor.mAppearence.getIcon();
721     }
722 
getDescription()723     String getDescription() {
724         return mNavigationCursor.getDetailedDescription();
725     }
726 
goToTitle(String title)727     public void goToTitle(String title) {
728         while (mNavigationCursor.mParent != null) {
729             mNavigationCursor = (Header) (mNavigationCursor.mParent);
730             if (TextUtils.equals(mNavigationCursor.mAppearence.mTitle, title)) {
731                 break;
732             }
733         }
734         updateLayoutRows();
735     }
736 
737     /*
738      * Respond to a user click on "layoutRow" and return "true" if the state of the display has
739      * changed. A controlling fragment will respond to a "true" return by updating the view.
740      */
onClickNavigate(LayoutRow layoutRow)741     public boolean onClickNavigate(LayoutRow layoutRow) {
742         LayoutTreeNode node = layoutRow.mNode;
743         if (node instanceof Header) {
744             mNavigationCursor.mSelectedIndex = mLayoutRows.indexOf(layoutRow);
745             mNavigationCursor = (Header) node;
746             updateLayoutRows();
747             return true;
748         }
749         return false;
750     }
751 
reloadLayoutRows()752     public void reloadLayoutRows() {
753         updateLayoutRows();
754     }
755 
add(Header header)756     public Layout add(Header header) {
757         header.mParent = null;
758         mChildren.add(header);
759         return this;
760     }
761 
add(LayoutTreeNode leaf)762     public Layout add(LayoutTreeNode leaf) {
763         leaf.mParent = null;
764         mChildren.add(leaf);
765         return this;
766     }
767 
breadcrumb(String topLevelBreadcrumb)768     public Layout breadcrumb(String topLevelBreadcrumb) {
769         mTopLevelBreadcrumb = topLevelBreadcrumb;
770         return this;
771     }
772 
773     /**
774      * Sets the selected node to the first top level node with its title member equal to "title". If
775      * "title" is null, empty, or there are no top level nodes with a title member equal to "title",
776      * set the first node in the list as the selected.
777      */
setSelectedByTitle(String title)778     public Layout setSelectedByTitle(String title) {
779         for (int i = 0; i < mChildren.size(); ++i) {
780             if (TextUtils.equals(mChildren.get(i).getTitle(), title)) {
781                 mInitialItemIndex = i;
782                 break;
783             }
784         }
785         return this;
786     }
787 
Log(int level)788     public void Log(int level) {
789         for (LayoutTreeNode i : mChildren) {
790             i.Log(level + 1);
791         }
792     }
793 
Log()794     public void Log() {
795         Log.d("Layout", "----- Layout");
796         Log(0);
797     }
798 
navigateToRoot()799     public void navigateToRoot() {
800         if (mChildren.size() > 0) {
801             mNavigationCursor = (Header) mChildren.get(0);
802         } else {
803             mNavigationCursor = null;
804         }
805         updateLayoutRows();
806     }
807 
getSelectedIndex()808     public int getSelectedIndex() {
809         return mNavigationCursor.mSelectedIndex;
810     }
811 
setSelectedIndex(int index)812     public void setSelectedIndex(int index) {
813         mNavigationCursor.mSelectedIndex = index;
814     }
815 
setParentSelectedIndex(int index)816     public void setParentSelectedIndex(int index) {
817         if (mNavigationCursor.mParent != null) {
818             Header u = (Header) mNavigationCursor.mParent;
819             u.mSelectedIndex = index;
820         }
821     }
822 
addNodeListToLayoutRows(ArrayList<LayoutTreeNode> list)823     private void addNodeListToLayoutRows(ArrayList<LayoutTreeNode> list) {
824         for (LayoutTreeNode node : list) {
825             if (node instanceof LayoutGetter) {
826                 // Add subitems of "node" recursively.
827                 LayoutGetter layoutGetter = (LayoutGetter) node;
828                 layoutGetter.setListener(mListener);
829                 mVisibleLayoutGetters.add(layoutGetter);
830                 Layout layout = layoutGetter.get();
831                 for (LayoutTreeNode child : layout.mChildren) {
832                     child.mParent = mNavigationCursor;
833                 }
834                 int initialIndex = layout.mInitialItemIndex;
835                 if (initialIndex != -1) {
836                     mNavigationCursor.mSelectedIndex = mLayoutRows.size() + initialIndex;
837                 }
838                 addNodeListToLayoutRows(layout.mChildren);
839             } else {
840                 if (node instanceof Action && ((Action) node).mDefaultSelection) {
841                     mNavigationCursor.mSelectedIndex = mLayoutRows.size();
842                 }
843                 mLayoutRows.add(new LayoutRow(node));
844             }
845         }
846     }
847 
updateLayoutRows()848     private void updateLayoutRows() {
849         mLayoutRows.clear();
850         for (LayoutGetter layoutGetter : mVisibleLayoutGetters) {
851             layoutGetter.notVisible();
852         }
853         mVisibleLayoutGetters.clear();
854         addNodeListToLayoutRows(mNavigationCursor.mChildren);
855     }
856 
indent(int level)857     private static String indent(int level) {
858         String s = new String();
859         for (int i = 0; i < level; ++i) {
860             s += "  ";
861         }
862         return s;
863     }
864 }
865