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