PhoneStatusBarView.java revision 1dacf2772d0099ae74f42f81d162a3d0e180ffb7
1/*
2 * Copyright (C) 2008 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.phone;
18
19import android.content.Context;
20import android.content.res.Configuration;
21import android.graphics.Canvas;
22import android.graphics.Rect;
23import android.os.SystemClock;
24import android.util.AttributeSet;
25import android.view.MotionEvent;
26import android.view.View;
27import android.view.ViewGroup;
28import android.view.ViewParent;
29import android.view.accessibility.AccessibilityEvent;
30import android.widget.FrameLayout;
31
32import com.android.systemui.R;
33import com.android.systemui.statusbar.policy.FixedSizeDrawable;
34
35public class PhoneStatusBarView extends FrameLayout {
36    private static final String TAG = "PhoneStatusBarView";
37
38    static final int DIM_ANIM_TIME = 400;
39
40    PhoneStatusBar mService;
41    boolean mTracking;
42    int mStartX, mStartY;
43    ViewGroup mNotificationIcons;
44    ViewGroup mStatusIcons;
45    View mDate;
46    FixedSizeDrawable mBackground;
47
48    boolean mNightMode = false;
49    int mStartAlpha = 0, mEndAlpha = 0;
50    long mEndTime = 0;
51
52    Rect mButtonBounds = new Rect();
53    boolean mCapturingEvents = true;
54
55    public PhoneStatusBarView(Context context, AttributeSet attrs) {
56        super(context, attrs);
57    }
58
59    @Override
60    protected void onFinishInflate() {
61        super.onFinishInflate();
62        mNotificationIcons = (ViewGroup)findViewById(R.id.notificationIcons);
63        mStatusIcons = (ViewGroup)findViewById(R.id.statusIcons);
64        mDate = findViewById(R.id.date);
65
66        mBackground = new FixedSizeDrawable(mDate.getBackground());
67        mBackground.setFixedBounds(0, 0, 0, 0);
68        mDate.setBackgroundDrawable(mBackground);
69    }
70
71    @Override
72    protected void onAttachedToWindow() {
73        super.onAttachedToWindow();
74        mService.onBarViewAttached();
75    }
76
77    @Override
78    protected void onConfigurationChanged(Configuration newConfig) {
79        super.onConfigurationChanged(newConfig);
80        mService.updateDisplaySize();
81        boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
82                == Configuration.UI_MODE_NIGHT_YES;
83        if (mNightMode != nightMode) {
84            mNightMode = nightMode;
85            mStartAlpha = getCurAlpha();
86            mEndAlpha = mNightMode ? 0x80 : 0x00;
87            mEndTime = SystemClock.uptimeMillis() + DIM_ANIM_TIME;
88            invalidate();
89        }
90    }
91
92    int getCurAlpha() {
93        long time = SystemClock.uptimeMillis();
94        if (time > mEndTime) {
95            return mEndAlpha;
96        }
97        return mEndAlpha
98                - (int)(((mEndAlpha-mStartAlpha) * (mEndTime-time) / DIM_ANIM_TIME));
99    }
100
101    @Override
102    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
103        super.onSizeChanged(w, h, oldw, oldh);
104        mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
105    }
106
107    @Override
108    protected void onLayout(boolean changed, int l, int t, int r, int b) {
109        super.onLayout(changed, l, t, r, b);
110
111        // put the date date view quantized to the icons
112        int oldDateRight = mDate.getRight();
113        int newDateRight;
114
115        newDateRight = getDateSize(mNotificationIcons, oldDateRight,
116                getViewOffset(mNotificationIcons));
117        if (newDateRight < 0) {
118            int offset = getViewOffset(mStatusIcons);
119            if (oldDateRight < offset) {
120                newDateRight = oldDateRight;
121            } else {
122                newDateRight = getDateSize(mStatusIcons, oldDateRight, offset);
123                if (newDateRight < 0) {
124                    newDateRight = r;
125                }
126            }
127        }
128        int max = r - getPaddingRight();
129        if (newDateRight > max) {
130            newDateRight = max;
131        }
132
133        mDate.layout(mDate.getLeft(), mDate.getTop(), newDateRight, mDate.getBottom());
134        mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t));
135    }
136
137    @Override
138    protected void dispatchDraw(Canvas canvas) {
139        super.dispatchDraw(canvas);
140        int alpha = getCurAlpha();
141        if (alpha != 0) {
142            canvas.drawARGB(alpha, 0, 0, 0);
143        }
144        if (alpha != mEndAlpha) {
145            invalidate();
146        }
147    }
148
149    /**
150     * Gets the left position of v in this view.  Throws if v is not
151     * a child of this.
152     */
153    private int getViewOffset(View v) {
154        int offset = 0;
155        while (v != this) {
156            offset += v.getLeft();
157            ViewParent p = v.getParent();
158            if (v instanceof View) {
159                v = (View)p;
160            } else {
161                throw new RuntimeException(v + " is not a child of " + this);
162            }
163        }
164        return offset;
165    }
166
167    private int getDateSize(ViewGroup g, int w, int offset) {
168        final int N = g.getChildCount();
169        for (int i=0; i<N; i++) {
170            View v = g.getChildAt(i);
171            int l = v.getLeft() + offset;
172            int r = v.getRight() + offset;
173            if (w >= l && w <= r) {
174                return r;
175            }
176        }
177        return -1;
178    }
179
180    /**
181     * Ensure that, if there is no target under us to receive the touch,
182     * that we process it ourself.  This makes sure that onInterceptTouchEvent()
183     * is always called for the entire gesture.
184     */
185    @Override
186    public boolean onTouchEvent(MotionEvent event) {
187        if (!mCapturingEvents) {
188            return false;
189        }
190        if (event.getAction() != MotionEvent.ACTION_DOWN) {
191            mService.interceptTouchEvent(event);
192        }
193        return true;
194    }
195
196    @Override
197    public boolean onInterceptTouchEvent(MotionEvent event) {
198        if (event.getAction() == MotionEvent.ACTION_DOWN) {
199            if (mButtonBounds.contains((int)event.getX(), (int)event.getY())) {
200                mCapturingEvents = false;
201                return false;
202            }
203        }
204        mCapturingEvents = true;
205        return mService.interceptTouchEvent(event)
206                ? true : super.onInterceptTouchEvent(event);
207    }
208
209    @Override
210    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
211        if (super.onRequestSendAccessibilityEvent(child, event)) {
212            // The status bar is very small so augment the view that the user is touching
213            // with the content of the status bar a whole. This way an accessibility service
214            // may announce the current item as well as the entire content if appropriate.
215            AccessibilityEvent record = AccessibilityEvent.obtain();
216            onInitializeAccessibilityEvent(record);
217            dispatchPopulateAccessibilityEvent(record);
218            event.appendRecord(record);
219            return true;
220        }
221        return false;
222    }
223}
224