KeyguardMessageArea.java revision c345146a3a321644f653fce0fb79f288a0221fb0
1/* 2 * Copyright (C) 2011 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.internal.policy.impl.keyguard; 18 19import android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.animation.ObjectAnimator; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.os.Handler; 25import android.os.Looper; 26import android.os.UserHandle; 27import android.provider.Settings; 28import android.text.TextUtils; 29import android.util.AttributeSet; 30import android.view.View; 31import android.widget.TextView; 32 33import libcore.util.MutableInt; 34 35import com.android.internal.R; 36 37/*** 38 * Manages a number of views inside of the given layout. See below for a list of widgets. 39 */ 40class KeyguardMessageArea extends TextView { 41 static final int CHARGING_ICON = 0; //R.drawable.ic_lock_idle_charging; 42 static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery; 43 44 static final int SECURITY_MESSAGE_DURATION = 5000; 45 protected static final int FADE_DURATION = 750; 46 static final String SEPARATOR = " "; 47 48 // are we showing battery information? 49 boolean mShowingBatteryInfo = false; 50 51 // is the bouncer up? 52 boolean mShowingBouncer = false; 53 54 // last known plugged in state 55 boolean mPluggedIn = false; 56 57 // last known battery level 58 int mBatteryLevel = 100; 59 60 KeyguardUpdateMonitor mUpdateMonitor; 61 62 // Timeout before we reset the message to show charging/owner info 63 long mTimeout = SECURITY_MESSAGE_DURATION; 64 65 // Shadowed text values 66 protected boolean mBatteryCharged; 67 protected boolean mBatteryIsLow; 68 69 private Handler mHandler; 70 71 CharSequence mMessage; 72 boolean mShowingMessage; 73 Runnable mClearMessageRunnable = new Runnable() { 74 @Override 75 public void run() { 76 mMessage = null; 77 mShowingMessage = false; 78 if (mShowingBouncer) { 79 hideMessage(FADE_DURATION, true); 80 } else { 81 update(); 82 } 83 } 84 }; 85 86 public static class Helper implements SecurityMessageDisplay { 87 KeyguardMessageArea mMessageArea; 88 Helper(View v) { 89 mMessageArea = (KeyguardMessageArea) v.findViewById(R.id.keyguard_message_area); 90 if (mMessageArea == null) { 91 throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass()); 92 } 93 } 94 95 public void setMessage(CharSequence msg, boolean important) { 96 if (!TextUtils.isEmpty(msg) && important) { 97 mMessageArea.mMessage = msg; 98 mMessageArea.securityMessageChanged(); 99 } 100 } 101 102 public void setMessage(int resId, boolean important) { 103 if (resId != 0 && important) { 104 mMessageArea.mMessage = mMessageArea.getContext().getResources().getText(resId); 105 mMessageArea.securityMessageChanged(); 106 } 107 } 108 109 public void setMessage(int resId, boolean important, Object... formatArgs) { 110 if (resId != 0 && important) { 111 mMessageArea.mMessage = mMessageArea.getContext().getString(resId, formatArgs); 112 mMessageArea.securityMessageChanged(); 113 } 114 } 115 116 @Override 117 public void showBouncer(int duration) { 118 mMessageArea.hideMessage(duration, false); 119 mMessageArea.mShowingBouncer = true; 120 } 121 122 @Override 123 public void hideBouncer(int duration) { 124 mMessageArea.showMessage(duration); 125 mMessageArea.mShowingBouncer = false; 126 } 127 128 @Override 129 public void setTimeout(int timeoutMs) { 130 mMessageArea.mTimeout = timeoutMs; 131 } 132 } 133 134 private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { 135 @Override 136 public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) { 137 mShowingBatteryInfo = status.isPluggedIn() || status.isBatteryLow(); 138 mPluggedIn = status.isPluggedIn(); 139 mBatteryLevel = status.level; 140 mBatteryCharged = status.isCharged(); 141 mBatteryIsLow = status.isBatteryLow(); 142 update(); 143 } 144 }; 145 146 public KeyguardMessageArea(Context context) { 147 this(context, null); 148 } 149 150 public KeyguardMessageArea(Context context, AttributeSet attrs) { 151 super(context, attrs); 152 153 // This is required to ensure marquee works 154 setSelected(true); 155 156 // Registering this callback immediately updates the battery state, among other things. 157 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(getContext()); 158 mUpdateMonitor.registerCallback(mInfoCallback); 159 mHandler = new Handler(Looper.myLooper()); 160 161 update(); 162 } 163 164 public void securityMessageChanged() { 165 setAlpha(1f); 166 mShowingMessage = true; 167 update(); 168 mHandler.removeCallbacks(mClearMessageRunnable); 169 if (mTimeout > 0) { 170 mHandler.postDelayed(mClearMessageRunnable, mTimeout); 171 } 172 announceForAccessibility(getText()); 173 } 174 175 /** 176 * Update the status lines based on these rules: 177 * AlarmStatus: Alarm state always gets it's own line. 178 * Status1 is shared between help, battery status and generic unlock instructions, 179 * prioritized in that order. 180 * @param showStatusLines status lines are shown if true 181 */ 182 void update() { 183 MutableInt icon = new MutableInt(0); 184 CharSequence status = concat(getChargeInfo(icon), getOwnerInfo(), getCurrentMessage()); 185 setCompoundDrawablesWithIntrinsicBounds(icon.value, 0, 0, 0); 186 setText(status); 187 } 188 189 190 private CharSequence concat(Object... args) { 191 StringBuilder b = new StringBuilder(); 192 for (int i = 0; i < args.length; i++) { 193 final Object arg = args[i]; 194 if (arg instanceof CharSequence) { 195 b.append((CharSequence)args[i]); 196 b.append(SEPARATOR); 197 } else if (arg instanceof String) { 198 b.append((String)args[i]); 199 b.append(SEPARATOR); 200 } 201 } 202 return b.toString(); 203 } 204 205 206 CharSequence getCurrentMessage() { 207 return mShowingMessage ? mMessage : null; 208 } 209 210 String getOwnerInfo() { 211 ContentResolver res = getContext().getContentResolver(); 212 final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res, 213 Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0; 214 return ownerInfoEnabled && !mShowingMessage ? 215 Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO, 216 UserHandle.USER_CURRENT) : null; 217 } 218 219 private CharSequence getChargeInfo(MutableInt icon) { 220 CharSequence string = null; 221 if (mShowingBatteryInfo && !mShowingMessage) { 222 // Battery status 223 if (mPluggedIn) { 224 // Charging, charged or waiting to charge. 225 string = getContext().getString(mBatteryCharged ? 226 com.android.internal.R.string.lockscreen_charged 227 :com.android.internal.R.string.lockscreen_plugged_in, mBatteryLevel); 228 icon.value = CHARGING_ICON; 229 } else if (mBatteryIsLow) { 230 // Battery is low 231 string = getContext().getString( 232 com.android.internal.R.string.lockscreen_low_battery); 233 icon.value = BATTERY_LOW_ICON; 234 } 235 } 236 return string; 237 } 238 239 private void hideMessage(int duration, boolean thenUpdate) { 240 Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f); 241 anim.setDuration(duration); 242 if (thenUpdate) { 243 anim.addListener(new AnimatorListenerAdapter() { 244 @Override 245 public void onAnimationEnd(Animator animation) { 246 update(); 247 } 248 }); 249 } 250 anim.start(); 251 } 252 253 private void showMessage(int duration) { 254 Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f); 255 anim.setDuration(duration); 256 anim.start(); 257 } 258} 259