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.Context;
     22 import android.content.res.Configuration;
     23 import android.content.res.Resources;
     24 import android.os.UserHandle;
     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 final LockPatternUtils mLockPatternUtils;
     45     private final AlarmManager mAlarmManager;
     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 onStartedWakingUp() {
     70             setEnableMarquee(true);
     71         }
     72 
     73         @Override
     74         public void onFinishedGoingToSleep(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         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     96         mLockPatternUtils = new LockPatternUtils(getContext());
     97     }
     98 
     99     private void setEnableMarquee(boolean enabled) {
    100         if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
    101         if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
    102         if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
    103     }
    104 
    105     @Override
    106     protected void onFinishInflate() {
    107         super.onFinishInflate();
    108         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
    109         mDateView = (TextClock) findViewById(R.id.date_view);
    110         mClockView = (TextClock) findViewById(R.id.clock_view);
    111         mDateView.setShowCurrentUserTime(true);
    112         mClockView.setShowCurrentUserTime(true);
    113         mOwnerInfo = (TextView) findViewById(R.id.owner_info);
    114 
    115         boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
    116         setEnableMarquee(shouldMarquee);
    117         refresh();
    118         updateOwnerInfo();
    119 
    120         // Disable elegant text height because our fancy colon makes the ymin value huge for no
    121         // reason.
    122         mClockView.setElegantTextHeight(false);
    123     }
    124 
    125     @Override
    126     protected void onConfigurationChanged(Configuration newConfig) {
    127         super.onConfigurationChanged(newConfig);
    128         mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
    129                 getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
    130         mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
    131                 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
    132         mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
    133                 getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
    134     }
    135 
    136     public void refreshTime() {
    137         mDateView.setFormat24Hour(Patterns.dateView);
    138         mDateView.setFormat12Hour(Patterns.dateView);
    139 
    140         mClockView.setFormat12Hour(Patterns.clockView12);
    141         mClockView.setFormat24Hour(Patterns.clockView24);
    142     }
    143 
    144     private void refresh() {
    145         AlarmManager.AlarmClockInfo nextAlarm =
    146                 mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
    147         Patterns.update(mContext, nextAlarm != null);
    148 
    149         refreshTime();
    150         refreshAlarmStatus(nextAlarm);
    151     }
    152 
    153     void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
    154         if (nextAlarm != null) {
    155             String alarm = formatNextAlarm(mContext, nextAlarm);
    156             mAlarmStatusView.setText(alarm);
    157             mAlarmStatusView.setContentDescription(
    158                     getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
    159             mAlarmStatusView.setVisibility(View.VISIBLE);
    160         } else {
    161             mAlarmStatusView.setVisibility(View.GONE);
    162         }
    163     }
    164 
    165     public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
    166         if (info == null) {
    167             return "";
    168         }
    169         String skeleton = DateFormat.is24HourFormat(context, ActivityManager.getCurrentUser())
    170                 ? "EHm"
    171                 : "Ehma";
    172         String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
    173         return DateFormat.format(pattern, info.getTriggerTime()).toString();
    174     }
    175 
    176     private void updateOwnerInfo() {
    177         if (mOwnerInfo == null) return;
    178         String ownerInfo = getOwnerInfo();
    179         if (!TextUtils.isEmpty(ownerInfo)) {
    180             mOwnerInfo.setVisibility(View.VISIBLE);
    181             mOwnerInfo.setText(ownerInfo);
    182         } else {
    183             mOwnerInfo.setVisibility(View.GONE);
    184         }
    185     }
    186 
    187     @Override
    188     protected void onAttachedToWindow() {
    189         super.onAttachedToWindow();
    190         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback);
    191     }
    192 
    193     @Override
    194     protected void onDetachedFromWindow() {
    195         super.onDetachedFromWindow();
    196         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback);
    197     }
    198 
    199     private String getOwnerInfo() {
    200         String info = null;
    201         if (mLockPatternUtils.isDeviceOwnerInfoEnabled()) {
    202             // Use the device owner information set by device policy client via
    203             // device policy manager.
    204             info = mLockPatternUtils.getDeviceOwnerInfo();
    205         } else {
    206             // Use the current user owner information if enabled.
    207             final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
    208                     KeyguardUpdateMonitor.getCurrentUser());
    209             if (ownerInfoEnabled) {
    210                 info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
    211             }
    212         }
    213         return info;
    214     }
    215 
    216     @Override
    217     public boolean hasOverlappingRendering() {
    218         return false;
    219     }
    220 
    221     // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
    222     // This is an optimization to ensure we only recompute the patterns when the inputs change.
    223     private static final class Patterns {
    224         static String dateView;
    225         static String clockView12;
    226         static String clockView24;
    227         static String cacheKey;
    228 
    229         static void update(Context context, boolean hasAlarm) {
    230             final Locale locale = Locale.getDefault();
    231             final Resources res = context.getResources();
    232             final String dateViewSkel = res.getString(hasAlarm
    233                     ? R.string.abbrev_wday_month_day_no_year_alarm
    234                     : R.string.abbrev_wday_month_day_no_year);
    235             final String clockView12Skel = res.getString(R.string.clock_12hr_format);
    236             final String clockView24Skel = res.getString(R.string.clock_24hr_format);
    237             final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
    238             if (key.equals(cacheKey)) return;
    239 
    240             dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel);
    241 
    242             clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
    243             // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
    244             // format.  The following code removes the AM/PM indicator if we didn't want it.
    245             if (!clockView12Skel.contains("a")) {
    246                 clockView12 = clockView12.replaceAll("a", "").trim();
    247             }
    248 
    249             clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
    250 
    251             // Use fancy colon.
    252             clockView24 = clockView24.replace(':', '\uee01');
    253             clockView12 = clockView12.replace(':', '\uee01');
    254 
    255             cacheKey = key;
    256         }
    257     }
    258 }
    259