blob: c830ff84fa260474a5558af72c0826cd1afdea88 [file] [log] [blame]
Rakesh Iyer5b3278f2017-04-19 11:28:26 -07001/*
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 com.android.systemui.statusbar.car;
18
19import android.content.Context;
20import android.content.res.TypedArray;
21import android.database.DataSetObserver;
22import android.graphics.Canvas;
23import android.graphics.Paint;
24import android.support.v4.view.PagerAdapter;
25import android.support.v4.view.ViewPager;
26import android.util.AttributeSet;
27import android.util.Log;
28import android.util.TypedValue;
29import android.view.Gravity;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.ViewParent;
33
34import com.android.systemui.R;
35
36import java.lang.ref.WeakReference;
37
38/**
39 * Displays the dots underneath the ViewPager on the lock screen. This is really just a simplified
40 * version of PagerTitleStrip. We don't inherit from there because it's impossible to bypass some
41 * of the overriden logic in that class.
42 */
43public class PageIndicator extends View {
44 private static final String TAG = "PageIndicator";
45 // These can be made a styleable attribute in the future if necessary.
46 private static final int SELECTED_COLOR = 0xFFF5F5F5; // grey 100
47 private static final int UNSELECTED_COLOR = 0xFFBDBDBD; // grey 400
48 private final PageListener mPageListener = new PageListener();
49
50 private ViewPager mPager;
51 private WeakReference<PagerAdapter> mWatchingAdapter;
52
53 private int mPageCount;
54 private int mCurrentPosition;
55 private Paint mPaint;
56 private int mRadius;
57 private int mStep;
58
59 public PageIndicator(Context context) {
60 super(context);
61 init();
62 }
63
64 public PageIndicator(Context context, AttributeSet attrs) {
65 super(context, attrs);
66 init();
67 }
68
69 private void init() {
70 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
71 mPaint.setStyle(Paint.Style.FILL);
72 mRadius = getResources().getDimensionPixelSize(R.dimen.car_page_indicator_dot_diameter) / 2;
73 mStep = mRadius * 3;
74 }
75
76 public void setupWithViewPager(ViewPager pager) {
77 mPager = pager;
78
79 final PagerAdapter adapter = (PagerAdapter) pager.getAdapter();
80 pager.addOnPageChangeListener(mPageListener);
81 pager.addOnAdapterChangeListener(mPageListener);
82 updateAdapter(mWatchingAdapter != null ? mWatchingAdapter.get() : null, adapter);
83 invalidate();
84 }
85
86 @Override
87 protected void onDetachedFromWindow() {
88 super.onDetachedFromWindow();
89 if (mPager != null) {
90 updateAdapter(mPager.getAdapter(), null);
91 mPager.removeOnPageChangeListener(mPageListener);
92 mPager.removeOnAdapterChangeListener(mPageListener);
93 mPager = null;
94 }
95 }
96
97 @Override
98 protected void onDraw(Canvas canvas) {
99 super.onDraw(canvas);
100
Bryan Eyler8991d652017-07-19 13:19:36 -0700101 // Don't draw anything unless there's multiple pages to scroll through. No need to clear
102 // any previous dots, since onDraw provides a canvas that's already cleared.
103 if (mPageCount <= 1)
104 return;
105
Rakesh Iyer5b3278f2017-04-19 11:28:26 -0700106 int x = canvas.getWidth() / 2 - (mPageCount / 2) * mStep;
107 int y = canvas.getHeight() / 2;
108
109 for (int i = 0; i < mPageCount; i++) {
110 if (i == mCurrentPosition) {
111 mPaint.setColor(SELECTED_COLOR);
112 } else {
113 mPaint.setColor(UNSELECTED_COLOR);
114 }
115
116 canvas.drawCircle(x, y, mRadius, mPaint);
117 x += mStep;
118 }
119 }
120
121 void updateAdapter(PagerAdapter oldAdapter, PagerAdapter newAdapter) {
122 if (oldAdapter != null) {
123 oldAdapter.unregisterDataSetObserver(mPageListener);
124 mWatchingAdapter = null;
125 }
126
127 if (newAdapter != null) {
128 newAdapter.registerDataSetObserver(mPageListener);
129 mWatchingAdapter = new WeakReference<>(newAdapter);
130 }
131
132 updateDots();
133
134 if (mPager != null) {
135 requestLayout();
136 }
137 }
138
139 private <T> T getRef(WeakReference<T> weakRef) {
140 if (weakRef == null) {
141 return null;
142 }
143 return weakRef.get();
144 }
145
146 private void updateDots() {
147 PagerAdapter adapter = getRef(mWatchingAdapter);
148 if (adapter == null) {
149 return;
150 }
151
152 int count = adapter.getCount();
153 if (mPageCount == count) {
154 // Nothing to be done.
155 return;
156 }
157
158 mPageCount = count;
159 mCurrentPosition = 0;
160 invalidate();
161 }
162
163 private class PageListener extends DataSetObserver implements ViewPager.OnPageChangeListener,
164 ViewPager.OnAdapterChangeListener {
165
166 @Override
167 public void onPageScrolled(int unused1, float unused2, int unused3) { }
168
169 @Override
170 public void onPageSelected(int position) {
171 if (mCurrentPosition == position) {
172 return;
173 }
174
175 if (mPageCount <= position) {
176 Log.e(TAG, "Position out of bounds, position=" + position + " size=" + mPageCount);
177 return;
178 }
179
180 mCurrentPosition = position;
181 invalidate();
182 }
183
184 @Override
185 public void onPageScrollStateChanged(int state) { }
186
187 @Override
188 public void onAdapterChanged(ViewPager viewPager, PagerAdapter oldAdapter,
189 PagerAdapter newAdapter) {
190 updateAdapter(oldAdapter, newAdapter);
191 }
192
193 @Override
194 public void onChanged() {
195 updateDots();
196 }
197 }
198}