1/* 2 * Copyright (C) 2017 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 17package android.support.wear.internal.widget.drawer; 18 19import android.graphics.drawable.Drawable; 20import android.support.annotation.Nullable; 21import android.support.annotation.RestrictTo; 22import android.support.annotation.RestrictTo.Scope; 23import android.support.wear.widget.drawer.WearableNavigationDrawerView; 24import android.support.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter; 25 26/** 27 * Provides a {@link WearableNavigationDrawerPresenter} implementation that is designed for the 28 * single page navigation drawer. 29 * 30 * @hide 31 */ 32@RestrictTo(Scope.LIBRARY_GROUP) 33public class SinglePagePresenter extends WearableNavigationDrawerPresenter { 34 35 private static final long DRAWER_CLOSE_DELAY_MS = 500; 36 37 private final Ui mUi; 38 private final boolean mIsAccessibilityEnabled; 39 @Nullable 40 private WearableNavigationDrawerAdapter mAdapter; 41 private int mCount = 0; 42 private int mSelected = 0; 43 44 /** 45 * Controls the user interface of a single-page {@link WearableNavigationDrawerView}. 46 */ 47 public interface Ui { 48 49 /** 50 * Associates a {@link WearableNavigationDrawerPresenter} with this {@link Ui}. 51 */ 52 void setPresenter(WearableNavigationDrawerPresenter presenter); 53 54 /** 55 * Initializes the {@link Ui} with {@code count} items. 56 */ 57 void initialize(int count); 58 59 /** 60 * Sets the item's {@link Drawable} icon and its {@code contentDescription}. 61 */ 62 void setIcon(int index, Drawable drawable, CharSequence contentDescription); 63 64 /** 65 * Displays {@code itemText} in a {@link android.widget.TextView} used to indicate which 66 * item is selected. When the {@link Ui} doesn't have space, it should show a {@link 67 * android.widget.Toast} if {@code showToastIfNoTextView} is {@code true}. 68 */ 69 void setText(CharSequence itemText, boolean showToastIfNoTextView); 70 71 /** 72 * Indicates that the item at {@code index} has been selected. 73 */ 74 void selectItem(int index); 75 76 /** 77 * Removes the indication that the item at {@code index} has been selected. 78 */ 79 void deselectItem(int index); 80 81 /** 82 * Closes the drawer after the given delay. 83 */ 84 void closeDrawerDelayed(long delayMs); 85 86 /** 87 * Peeks the {@link WearableNavigationDrawerView}. 88 */ 89 void peekDrawer(); 90 } 91 92 public SinglePagePresenter(Ui ui, boolean isAccessibilityEnabled) { 93 if (ui == null) { 94 throw new IllegalArgumentException("Received null ui."); 95 } 96 97 mIsAccessibilityEnabled = isAccessibilityEnabled; 98 mUi = ui; 99 mUi.setPresenter(this); 100 onDataSetChanged(); 101 } 102 103 @Override 104 public void onDataSetChanged() { 105 if (mAdapter == null) { 106 return; 107 } 108 int count = mAdapter.getCount(); 109 if (mCount != count) { 110 mCount = count; 111 mSelected = Math.min(mSelected, count - 1); 112 mUi.initialize(count); 113 } 114 for (int i = 0; i < count; i++) { 115 mUi.setIcon(i, mAdapter.getItemDrawable(i), mAdapter.getItemText(i)); 116 } 117 118 mUi.setText(mAdapter.getItemText(mSelected), false /* showToastIfNoTextView */); 119 mUi.selectItem(mSelected); 120 } 121 122 @Override 123 public void onNewAdapter(WearableNavigationDrawerAdapter adapter) { 124 if (adapter == null) { 125 throw new IllegalArgumentException("Received null adapter."); 126 } 127 mAdapter = adapter; 128 mAdapter.setPresenter(this); 129 onDataSetChanged(); 130 } 131 132 @Override 133 public void onSelected(int index) { 134 mUi.deselectItem(mSelected); 135 mUi.selectItem(index); 136 mSelected = index; 137 if (mIsAccessibilityEnabled) { 138 // When accessibility gestures are enabled, the user can't access a closed nav drawer, 139 // so peek it instead. 140 mUi.peekDrawer(); 141 } else { 142 mUi.closeDrawerDelayed(DRAWER_CLOSE_DELAY_MS); 143 } 144 145 if (mAdapter != null) { 146 mUi.setText(mAdapter.getItemText(index), true /* showToastIfNoTextView */); 147 } 148 notifyItemSelectedListeners(index); 149 } 150 151 @Override 152 public void onSetCurrentItemRequested(int index, boolean smoothScrollTo) { 153 mUi.deselectItem(mSelected); 154 mUi.selectItem(index); 155 mSelected = index; 156 if (mAdapter != null) { 157 mUi.setText(mAdapter.getItemText(index), false /* showToastIfNoTextView */); 158 } 159 notifyItemSelectedListeners(index); 160 } 161 162 @Override 163 public boolean onDrawerTapped() { 164 // Do nothing. Use onSelected as our tap trigger so that we get which index was tapped on. 165 return false; 166 } 167} 168