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 androidx.wear.internal.widget.drawer; 18 19import android.graphics.drawable.Drawable; 20import android.os.Handler; 21import android.os.Looper; 22import android.view.Gravity; 23import android.view.LayoutInflater; 24import android.view.View; 25import android.widget.TextView; 26import android.widget.Toast; 27 28import androidx.annotation.IdRes; 29import androidx.annotation.LayoutRes; 30import androidx.annotation.Nullable; 31import androidx.annotation.RestrictTo; 32import androidx.annotation.RestrictTo.Scope; 33import androidx.wear.R; 34import androidx.wear.widget.CircledImageView; 35import androidx.wear.widget.drawer.WearableNavigationDrawerView; 36 37/** 38 * Handles view logic for the single page style {@link WearableNavigationDrawerView}. 39 * 40 * @hide 41 */ 42@RestrictTo(Scope.LIBRARY) 43public class SinglePageUi implements SinglePagePresenter.Ui { 44 45 @IdRes 46 private static final int[] SINGLE_PAGE_BUTTON_IDS = 47 new int[]{ 48 R.id.ws_nav_drawer_icon_0, 49 R.id.ws_nav_drawer_icon_1, 50 R.id.ws_nav_drawer_icon_2, 51 R.id.ws_nav_drawer_icon_3, 52 R.id.ws_nav_drawer_icon_4, 53 R.id.ws_nav_drawer_icon_5, 54 R.id.ws_nav_drawer_icon_6, 55 }; 56 57 @LayoutRes 58 private static final int[] SINGLE_PAGE_LAYOUT_RES = 59 new int[]{ 60 0, 61 R.layout.ws_single_page_nav_drawer_1_item, 62 R.layout.ws_single_page_nav_drawer_2_item, 63 R.layout.ws_single_page_nav_drawer_3_item, 64 R.layout.ws_single_page_nav_drawer_4_item, 65 R.layout.ws_single_page_nav_drawer_5_item, 66 R.layout.ws_single_page_nav_drawer_6_item, 67 R.layout.ws_single_page_nav_drawer_7_item, 68 }; 69 70 private final WearableNavigationDrawerView mDrawer; 71 private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); 72 private final Runnable mCloseDrawerRunnable = 73 new Runnable() { 74 @Override 75 public void run() { 76 mDrawer.getController().closeDrawer(); 77 } 78 }; 79 private WearableNavigationDrawerPresenter mPresenter; 80 private CircledImageView[] mSinglePageImageViews; 81 /** 82 * Indicates currently selected item. {@code null} when the layout lacks space to display it. 83 */ 84 @Nullable 85 private TextView mTextView; 86 87 public SinglePageUi(WearableNavigationDrawerView navigationDrawer) { 88 if (navigationDrawer == null) { 89 throw new IllegalArgumentException("Received null navigationDrawer."); 90 } 91 mDrawer = navigationDrawer; 92 } 93 94 @Override 95 public void setPresenter(WearableNavigationDrawerPresenter presenter) { 96 mPresenter = presenter; 97 } 98 99 @Override 100 public void initialize(int count) { 101 if (count < 0 || count >= SINGLE_PAGE_LAYOUT_RES.length 102 || SINGLE_PAGE_LAYOUT_RES[count] == 0) { 103 mDrawer.setDrawerContent(null); 104 return; 105 } 106 107 @LayoutRes int layoutRes = SINGLE_PAGE_LAYOUT_RES[count]; 108 LayoutInflater inflater = LayoutInflater.from(mDrawer.getContext()); 109 View content = inflater.inflate(layoutRes, mDrawer, false /* attachToRoot */); 110 final View peek = 111 inflater.inflate( 112 R.layout.ws_single_page_nav_drawer_peek_view, mDrawer, 113 false /* attachToRoot */); 114 115 mTextView = content.findViewById(R.id.ws_nav_drawer_text); 116 mSinglePageImageViews = new CircledImageView[count]; 117 for (int i = 0; i < count; i++) { 118 mSinglePageImageViews[i] = content.findViewById(SINGLE_PAGE_BUTTON_IDS[i]); 119 mSinglePageImageViews[i].setOnClickListener(new OnSelectedClickHandler(i, mPresenter)); 120 mSinglePageImageViews[i].setCircleHidden(true); 121 } 122 123 mDrawer.setDrawerContent(content); 124 mDrawer.setPeekContent(peek); 125 } 126 127 @Override 128 public void setIcon(int index, Drawable drawable, CharSequence contentDescription) { 129 mSinglePageImageViews[index].setImageDrawable(drawable); 130 mSinglePageImageViews[index].setContentDescription(contentDescription); 131 } 132 133 @Override 134 public void setText(CharSequence itemText, boolean showToastIfNoTextView) { 135 if (mTextView != null) { 136 mTextView.setText(itemText); 137 } else if (showToastIfNoTextView) { 138 Toast toast = Toast.makeText(mDrawer.getContext(), itemText, Toast.LENGTH_SHORT); 139 toast.setGravity(Gravity.CENTER, 0 /* xOffset */, 0 /* yOffset */); 140 toast.show(); 141 } 142 } 143 144 @Override 145 public void selectItem(int index) { 146 mSinglePageImageViews[index].setCircleHidden(false); 147 } 148 149 @Override 150 public void deselectItem(int index) { 151 mSinglePageImageViews[index].setCircleHidden(true); 152 } 153 154 @Override 155 public void closeDrawerDelayed(long delayMs) { 156 mMainThreadHandler.removeCallbacks(mCloseDrawerRunnable); 157 mMainThreadHandler.postDelayed(mCloseDrawerRunnable, delayMs); 158 } 159 160 @Override 161 public void peekDrawer() { 162 mDrawer.getController().peekDrawer(); 163 } 164 165 /** 166 * Notifies the {@code presenter} that the item at the given {@code index} has been selected. 167 */ 168 private static class OnSelectedClickHandler implements View.OnClickListener { 169 170 private final int mIndex; 171 private final WearableNavigationDrawerPresenter mPresenter; 172 173 private OnSelectedClickHandler(int index, WearableNavigationDrawerPresenter presenter) { 174 mIndex = index; 175 mPresenter = presenter; 176 } 177 178 @Override 179 public void onClick(View v) { 180 mPresenter.onSelected(mIndex); 181 } 182 } 183} 184