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