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