KeyguardStatusView.java revision 93afa1dba63311dfdd43da82fed765240857ee30
1/*
2 * Copyright (C) 2012 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.keyguard;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.content.res.Resources;
22import android.text.TextUtils;
23import android.text.format.DateFormat;
24import android.util.AttributeSet;
25import android.util.Log;
26import android.util.Slog;
27import android.view.View;
28import android.widget.GridLayout;
29import android.widget.TextClock;
30import android.widget.TextView;
31
32import com.android.internal.widget.LockPatternUtils;
33
34import java.util.Locale;
35
36public class KeyguardStatusView extends GridLayout {
37    private static final boolean DEBUG = KeyguardConstants.DEBUG;
38    private static final String TAG = "KeyguardStatusView";
39
40    private LockPatternUtils mLockPatternUtils;
41
42    private TextView mAlarmStatusView;
43    private TextClock mDateView;
44    private TextClock mClockView;
45    private TextView mOwnerInfo;
46
47    private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
48
49        @Override
50        public void onTimeChanged() {
51            refresh();
52        }
53
54        @Override
55        public void onKeyguardVisibilityChanged(boolean showing) {
56            if (showing) {
57                if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
58                refresh();
59                updateOwnerInfo();
60            }
61        }
62
63        @Override
64        public void onScreenTurnedOn() {
65            setEnableMarquee(true);
66        }
67
68        @Override
69        public void onScreenTurnedOff(int why) {
70            setEnableMarquee(false);
71        }
72    };
73
74    public KeyguardStatusView(Context context) {
75        this(context, null, 0);
76    }
77
78    public KeyguardStatusView(Context context, AttributeSet attrs) {
79        this(context, attrs, 0);
80    }
81
82    public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
83        super(context, attrs, defStyle);
84    }
85
86    private void setEnableMarquee(boolean enabled) {
87        if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
88        if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
89        mOwnerInfo.setSelected(enabled);
90    }
91
92    @Override
93    protected void onFinishInflate() {
94        super.onFinishInflate();
95        mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
96        mDateView = (TextClock) findViewById(R.id.date_view);
97        mClockView = (TextClock) findViewById(R.id.clock_view);
98        mOwnerInfo = (TextView) findViewById(R.id.owner_info);
99        mLockPatternUtils = new LockPatternUtils(getContext());
100        final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
101        setEnableMarquee(screenOn);
102        refresh();
103        updateOwnerInfo();
104
105        // Disable elegant text height because our fancy colon makes the ymin value huge for no
106        // reason.
107        mClockView.setElegantTextHeight(false);
108    }
109
110    protected void refresh() {
111        Patterns.update(mContext);
112
113        mDateView.setFormat24Hour(Patterns.dateView);
114        mDateView.setFormat12Hour(Patterns.dateView);
115
116        mClockView.setFormat12Hour(Patterns.clockView12);
117        mClockView.setFormat24Hour(Patterns.clockView24);
118
119        refreshAlarmStatus();
120    }
121
122    void refreshAlarmStatus() {
123        // Update Alarm status
124        String nextAlarm = mLockPatternUtils.getNextAlarm();
125        if (!TextUtils.isEmpty(nextAlarm)) {
126            mAlarmStatusView.setText(nextAlarm);
127            mAlarmStatusView.setVisibility(View.VISIBLE);
128        } else {
129            mAlarmStatusView.setVisibility(View.GONE);
130        }
131    }
132
133    private void updateOwnerInfo() {
134        String ownerInfo = getOwnerInfo();
135        if (!TextUtils.isEmpty(ownerInfo)) {
136            mOwnerInfo.setVisibility(View.VISIBLE);
137            mOwnerInfo.setText(ownerInfo);
138        } else {
139            mOwnerInfo.setVisibility(View.GONE);
140        }
141    }
142
143    @Override
144    protected void onAttachedToWindow() {
145        super.onAttachedToWindow();
146        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
147    }
148
149    @Override
150    protected void onDetachedFromWindow() {
151        super.onDetachedFromWindow();
152        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
153    }
154
155    public int getAppWidgetId() {
156        return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET;
157    }
158
159    private String getOwnerInfo() {
160        ContentResolver res = getContext().getContentResolver();
161        String info = null;
162        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
163        if (ownerInfoEnabled) {
164            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
165        }
166        return info;
167    }
168
169    // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
170    // This is an optimization to ensure we only recompute the patterns when the inputs change.
171    private static final class Patterns {
172        static String dateView;
173        static String clockView12;
174        static String clockView24;
175        static String cacheKey;
176
177        static void update(Context context) {
178            final Locale locale = Locale.getDefault();
179            final Resources res = context.getResources();
180            final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year);
181            final String clockView12Skel = res.getString(R.string.clock_12hr_format);
182            final String clockView24Skel = res.getString(R.string.clock_24hr_format);
183            final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
184            if (key.equals(cacheKey)) return;
185
186            dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel);
187
188            clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
189            // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
190            // format.  The following code removes the AM/PM indicator if we didn't want it.
191            if (!clockView12Skel.contains("a")) {
192                clockView12 = clockView12.replaceAll("a", "").trim();
193            }
194
195            clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
196
197            // Use fancy colon.
198            clockView24 = clockView24.replace(':', '\uee01');
199            clockView12 = clockView12.replace(':', '\uee01');
200
201            cacheKey = key;
202        }
203    }
204}
205