Home | History | Annotate | Download | only in car
      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 
     17 package com.android.systemui.statusbar.car;
     18 
     19 import android.content.Context;
     20 import android.content.res.TypedArray;
     21 import android.database.DataSetObserver;
     22 import android.graphics.Canvas;
     23 import android.graphics.Paint;
     24 import android.support.v4.view.PagerAdapter;
     25 import android.support.v4.view.ViewPager;
     26 import android.util.AttributeSet;
     27 import android.util.Log;
     28 import android.util.TypedValue;
     29 import android.view.Gravity;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 import android.view.ViewParent;
     33 
     34 import com.android.systemui.R;
     35 
     36 import 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  */
     43 public 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 
    101         // 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 
    106         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 }
    199