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.util.Log;
20import android.view.LayoutInflater;
21import android.view.View;
22import android.view.ViewGroup;
23import android.widget.ImageView;
24import android.widget.TextView;
25
26import androidx.annotation.NonNull;
27import androidx.annotation.Nullable;
28import androidx.annotation.RestrictTo;
29import androidx.annotation.RestrictTo.Scope;
30import androidx.viewpager.widget.PagerAdapter;
31import androidx.viewpager.widget.ViewPager;
32import androidx.wear.R;
33import androidx.wear.widget.drawer.PageIndicatorView;
34import androidx.wear.widget.drawer.WearableNavigationDrawerView;
35import androidx.wear.widget.drawer.WearableNavigationDrawerView.WearableNavigationDrawerAdapter;
36
37/**
38 * Handles view logic for the multi page style {@link WearableNavigationDrawerView}.
39 *
40 * @hide
41 */
42@RestrictTo(Scope.LIBRARY)
43public class MultiPageUi implements MultiPagePresenter.Ui {
44
45    private static final String TAG = "MultiPageUi";
46
47    private WearableNavigationDrawerPresenter mPresenter;
48
49    @Nullable private ViewPager mNavigationPager;
50    @Nullable private PageIndicatorView mPageIndicatorView;
51
52    @Override
53    public void initialize(
54            WearableNavigationDrawerView drawer, WearableNavigationDrawerPresenter presenter) {
55        if (drawer == null) {
56            throw new IllegalArgumentException("Received null drawer.");
57        }
58        if (presenter == null) {
59            throw new IllegalArgumentException("Received null presenter.");
60        }
61        mPresenter = presenter;
62
63        LayoutInflater inflater = LayoutInflater.from(drawer.getContext());
64        final View content = inflater.inflate(R.layout.ws_navigation_drawer_view, drawer,
65                false /* attachToRoot */);
66
67        mNavigationPager = content.findViewById(R.id.ws_navigation_drawer_view_pager);
68        mPageIndicatorView = content.findViewById(R.id.ws_navigation_drawer_page_indicator);
69
70        drawer.setDrawerContent(content);
71    }
72
73    @Override
74    public void setNavigationPagerAdapter(final WearableNavigationDrawerAdapter adapter) {
75        if (mNavigationPager == null || mPageIndicatorView == null) {
76            Log.w(TAG, "setNavigationPagerAdapter was called before initialize.");
77            return;
78        }
79
80        NavigationPagerAdapter navigationPagerAdapter = new NavigationPagerAdapter(adapter);
81        mNavigationPager.setAdapter(navigationPagerAdapter);
82
83        // Clear out the old page listeners and add a new one for this adapter.
84        mNavigationPager.clearOnPageChangeListeners();
85        mNavigationPager.addOnPageChangeListener(
86                new ViewPager.SimpleOnPageChangeListener() {
87                    @Override
88                    public void onPageSelected(int position) {
89                        mPresenter.onSelected(position);
90                    }
91                });
92        // PageIndicatorView adds itself as a page change listener here, so this must come after
93        // they are cleared.
94        mPageIndicatorView.setPager(mNavigationPager);
95    }
96
97    @Override
98    public void notifyPageIndicatorDataChanged() {
99        if (mPageIndicatorView != null) {
100            mPageIndicatorView.notifyDataSetChanged();
101        }
102    }
103
104    @Override
105    public void notifyNavigationPagerAdapterDataChanged() {
106        if (mNavigationPager != null) {
107            PagerAdapter adapter = mNavigationPager.getAdapter();
108            if (adapter != null) {
109                adapter.notifyDataSetChanged();
110            }
111        }
112    }
113
114    @Override
115    public void setNavigationPagerSelectedItem(int index, boolean smoothScrollTo) {
116        if (mNavigationPager != null) {
117            mNavigationPager.setCurrentItem(index, smoothScrollTo);
118        }
119    }
120
121    /**
122     * Adapter for {@link ViewPager} used in the multi-page UI.
123     */
124    private static final class NavigationPagerAdapter extends PagerAdapter {
125
126        private final WearableNavigationDrawerAdapter mAdapter;
127
128        NavigationPagerAdapter(WearableNavigationDrawerAdapter adapter) {
129            mAdapter = adapter;
130        }
131
132        @NonNull
133        @Override
134        public Object instantiateItem(@NonNull ViewGroup container, int position) {
135            // Do not attach to root in the inflate method. The view needs to returned at the end
136            // of this method. Attaching to root will cause view to point to container instead.
137            final View view =
138                    LayoutInflater.from(container.getContext())
139                            .inflate(R.layout.ws_navigation_drawer_item_view, container, false);
140            container.addView(view);
141            final ImageView iconView =
142                    view.findViewById(R.id.ws_navigation_drawer_item_icon);
143            final TextView textView =
144                    view.findViewById(R.id.ws_navigation_drawer_item_text);
145            iconView.setImageDrawable(mAdapter.getItemDrawable(position));
146            textView.setText(mAdapter.getItemText(position));
147            return view;
148        }
149
150        @Override
151        public void destroyItem(@NonNull ViewGroup container, int position,
152                @NonNull Object object) {
153            container.removeView((View) object);
154        }
155
156        @Override
157        public int getCount() {
158            return mAdapter.getCount();
159        }
160
161        @Override
162        public int getItemPosition(@NonNull Object object) {
163            return POSITION_NONE;
164        }
165
166        @Override
167        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
168            return view == object;
169        }
170    }
171}
172