diff options
| author | DvTonder <david.vantonder@gmail.com> | 2012-07-15 10:28:15 -0400 |
|---|---|---|
| committer | Ricardo Cerqueira <cyanogenmod@cerqueira.org> | 2012-11-21 00:25:18 +0000 |
| commit | 0b636d08439c291322339e02be605be54f589b91 (patch) | |
| tree | 1abb1921eab3532617ddda7e07939f99de093280 /policy | |
| parent | 8415ee214d09ed7f399d8ff68d4f78c76c68fe08 (diff) | |
| download | frameworks_base-0b636d08439c291322339e02be605be54f589b91.zip frameworks_base-0b636d08439c291322339e02be605be54f589b91.tar.gz frameworks_base-0b636d08439c291322339e02be605be54f589b91.tar.bz2 | |
Framework: Port CM9 features to CM10
This commit includes:
- Power menu Reboot
- Power menu screenshot
- Profiles
- Lock screen Calendar
- Lock screen Weather
- Notification light customization
- Battery light customization
- IME Selector notification toggle
- and a few more things to support Settings
Change-Id: Ibd63116df90b06f6ce6adb8a0343059bbb999bfb
Diffstat (limited to 'policy')
4 files changed, 765 insertions, 44 deletions
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index d1f8ef1..6c439cc 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010-2012 CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +26,8 @@ import com.android.internal.R; import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.app.Dialog; +import android.app.Profile; +import android.app.ProfileManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -71,6 +74,17 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.List; +import java.util.UUID; + +/** + * Needed for takeScreenshot + */ +import android.content.ServiceConnection; +import android.content.ComponentName; +import android.os.IBinder; +import android.os.Messenger; +import android.os.RemoteException; + /** * Helper to show the global actions dialog. Each item is an {@link Action} that @@ -85,6 +99,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private final Context mContext; private final WindowManagerFuncs mWindowManagerFuncs; + private final AudioManager mAudioManager; private final IDreamManager mDreamManager; @@ -103,6 +118,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private boolean mHasTelephony; private boolean mHasVibrator; + private Profile mChosenProfile; + + /** * @param context everything needs a context :( */ @@ -242,6 +260,22 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mWindowManagerFuncs.shutdown(true); } + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return true; + } + }); + + // next: reboot + mItems.add( + new SinglePressAction(R.drawable.ic_lock_reboot, R.string.global_action_reboot) { + public void onPress() { + mWindowManagerFuncs.reboot(); + } + public boolean onLongPress() { mWindowManagerFuncs.rebootSafeMode(true); return true; @@ -256,6 +290,43 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } }); + + // next: profile + mItems.add( + new ProfileChooseAction() { + public void onPress() { + createProfileDialog(); + } + + public boolean onLongPress() { + return true; + } + + public boolean showDuringKeyguard() { + return false; + } + + public boolean showBeforeProvisioning() { + return false; + } + }); + + // next: screenshot + mItems.add( + new SinglePressAction(R.drawable.ic_lock_screenshot, R.string.global_action_screenshot) { + public void onPress() { + takeScreenshot(); + } + + public boolean showDuringKeyguard() { + return true; + } + + public boolean showBeforeProvisioning() { + return true; + } + }); + // next: airplane mode mItems.add(mAirplaneModeOn); @@ -385,11 +456,141 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } } + private void createProfileDialog(){ + final ProfileManager profileManager = (ProfileManager)mContext.getSystemService(Context.PROFILE_SERVICE); + + final Profile[] profiles = profileManager.getProfiles(); + UUID activeProfile = profileManager.getActiveProfile().getUuid(); + final CharSequence[] names = new CharSequence[profiles.length]; + + int i=0; + int checkedItem = 0; + + for(Profile profile : profiles) { + if(profile.getUuid().equals(activeProfile)) { + checkedItem = i; + mChosenProfile = profile; + } + names[i++] = profile.getName(); + } + + final AlertDialog.Builder ab = new AlertDialog.Builder(mContext); + + AlertDialog dialog = ab + .setTitle(R.string.global_action_choose_profile) + .setSingleChoiceItems(names, checkedItem, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if (which < 0) + return; + mChosenProfile = profiles[which]; + } + }) + .setPositiveButton(com.android.internal.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + profileManager.setActiveProfile(mChosenProfile.getUuid()); + } + }) + .setNegativeButton(com.android.internal.R.string.no, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }).create(); + dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + dialog.show(); + } + + /** + * functions needed for taking screenhots. + * This leverages the built in ICS screenshot functionality + */ + final Object mScreenshotLock = new Object(); + ServiceConnection mScreenshotConnection = null; + + final Runnable mScreenshotTimeout = new Runnable() { + @Override public void run() { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + } + } + } + }; + + private void takeScreenshot() { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + return; + } + ComponentName cn = new ComponentName("com.android.systemui", + "com.android.systemui.screenshot.TakeScreenshotService"); + Intent intent = new Intent(); + intent.setComponent(cn); + ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != this) { + return; + } + Messenger messenger = new Messenger(service); + Message msg = Message.obtain(null, 1); + final ServiceConnection myConn = this; + Handler h = new Handler(mHandler.getLooper()) { + @Override + public void handleMessage(Message msg) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection == myConn) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + mHandler.removeCallbacks(mScreenshotTimeout); + } + } + } + }; + msg.replyTo = new Messenger(h); + msg.arg1 = msg.arg2 = 0; + + /* remove for the time being + if (mStatusBar != null && mStatusBar.isVisibleLw()) + msg.arg1 = 1; + if (mNavigationBar != null && mNavigationBar.isVisibleLw()) + msg.arg2 = 1; + */ + + /* wait for the dialog box to close */ + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + } + + /* take the screenshot */ + try { + messenger.send(msg); + } catch (RemoteException e) { + } + } + } + @Override + public void onServiceDisconnected(ComponentName name) {} + }; + if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) { + mScreenshotConnection = conn; + mHandler.postDelayed(mScreenshotTimeout, 10000); + } + } + } + private void prepareDialog() { refreshSilentMode(); mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + + mDialog.setTitle(R.string.global_actions); + if (SHOW_SILENT_TOGGLE) { IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); mContext.registerReceiver(mRingerModeReceiver, filter); @@ -587,6 +788,41 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } /** + * A single press action maintains no state, just responds to a press + * and takes an action. + */ + private abstract class ProfileChooseAction implements Action { + private ProfileManager mProfileManager; + + protected ProfileChooseAction() { + mProfileManager = (ProfileManager)mContext.getSystemService(Context.PROFILE_SERVICE); + } + + public boolean isEnabled() { + return true; + } + + abstract public void onPress(); + + public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { + View v = (convertView != null) ? + convertView : + inflater.inflate(R.layout.global_actions_item, parent, false); + + ImageView icon = (ImageView) v.findViewById(R.id.icon); + TextView messageView = (TextView) v.findViewById(R.id.message); + TextView statusView = (TextView) v.findViewById(R.id.status); + statusView.setVisibility(View.VISIBLE); + statusView.setText(mProfileManager.getActiveProfile().getName()); + + icon.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_lock_profile)); + messageView.setText(R.string.global_action_choose_profile); + + return v; + } + } + + /** * A toggle action knows whether it is on or off, and displays an icon * and status message accordingly. */ diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index d9c07f8..a48e411 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -324,6 +324,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mFocusedWindow; IApplicationToken mFocusedApp; + // Behavior of volume wake + boolean mVolumeWakeScreen; + + // Behavior of volbtn music controls + boolean mVolBtnMusicControls; + boolean mIsLongPress; + private static final class PointerLocationInputEventReceiver extends InputEventReceiver { private final PointerLocationView mView; @@ -526,6 +533,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.VOLUME_WAKE_SCREEN), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.VOLBTN_MUSIC_CONTROLS), false, this, + UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION), false, this, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( @@ -675,6 +688,53 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + /** + * When a volumeup-key longpress expires, skip songs based on key press + */ + Runnable mVolumeUpLongPress = new Runnable() { + public void run() { + // set the long press flag to true + mIsLongPress = true; + + // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc... + sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_NEXT); + }; + }; + + /** + * When a volumedown-key longpress expires, skip songs based on key press + */ + Runnable mVolumeDownLongPress = new Runnable() { + public void run() { + // set the long press flag to true + mIsLongPress = true; + + // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc... + sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS); + }; + }; + + private void sendMediaButtonEvent(int code) { + long eventtime = SystemClock.uptimeMillis(); + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + KeyEvent keyEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, code, 0); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + mContext.sendOrderedBroadcast(keyIntent, null); + keyEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + mContext.sendOrderedBroadcast(keyIntent, null); + } + + void handleVolumeLongPress(int keycode) { + mHandler.postDelayed(keycode == KeyEvent.KEYCODE_VOLUME_UP ? mVolumeUpLongPress : + mVolumeDownLongPress, ViewConfiguration.getLongPressTimeout()); + } + + void handleVolumeLongPressAbort() { + mHandler.removeCallbacks(mVolumeUpLongPress); + mHandler.removeCallbacks(mVolumeDownLongPress); + } + private void interceptScreenshotChord() { if (mScreenshotChordEnabled && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { @@ -1070,11 +1130,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT, UserHandle.USER_CURRENT); + mVolumeWakeScreen = (Settings.System.getIntForUser(resolver, + Settings.System.VOLUME_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1); + mVolBtnMusicControls = (Settings.System.getIntForUser(resolver, + Settings.System.VOLBTN_MUSIC_CONTROLS, 1, UserHandle.USER_CURRENT) == 1); // Configure rotation lock. int userRotation = Settings.System.getIntForUser(resolver, Settings.System.USER_ROTATION, Surface.ROTATION_0, UserHandle.USER_CURRENT); + if (mUserRotation != userRotation) { mUserRotation = userRotation; updateRotation = true; @@ -3340,7 +3405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); - final int keyCode = event.getKeyCode(); + int keyCode = event.getKeyCode(); final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0; @@ -3356,8 +3421,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (keyCode == KeyEvent.KEYCODE_POWER) { policyFlags |= WindowManagerPolicy.FLAG_WAKE; } - final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE - | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + final boolean isWakeKey = (policyFlags + & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; if (DEBUG_INPUT) { Log.d(TAG, "interceptKeyTq keycode=" + keyCode @@ -3391,7 +3456,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (keyguardActive) { // If the keyguard is showing, let it wake the device when ready. mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode); - } else { + } else if ((keyCode != KeyEvent.KEYCODE_VOLUME_UP) && (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN)) { // Otherwise, wake the device ourselves. result |= ACTION_WAKE_UP; } @@ -3400,6 +3465,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Handle special keys. switch (keyCode) { + case KeyEvent.KEYCODE_ENDCALL: { + result &= ~ACTION_PASS_TO_USER; + if (down) { + ITelephony telephonyService = getTelephonyService(); + boolean hungUp = false; + if (telephonyService != null) { + try { + hungUp = telephonyService.endCall(); + } catch (RemoteException ex) { + Log.w(TAG, "ITelephony threw RemoteException", ex); + } + } + interceptPowerKeyDown(!isScreenOn || hungUp); + } else { + if (interceptPowerKeyUp(canceled)) { + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { + if (goHome()) { + break; + } + } + if ((mEndcallBehavior + & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { + result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP; + } + } + } + break; + } case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_MUTE: { @@ -3464,45 +3558,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { Log.w(TAG, "ITelephony threw RemoteException", ex); } } - - if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) { - // If music is playing but we decided not to pass the key to the - // application, handle the volume change here. - handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode); - break; - } } - break; - } - - case KeyEvent.KEYCODE_ENDCALL: { - result &= ~ACTION_PASS_TO_USER; - if (down) { - ITelephony telephonyService = getTelephonyService(); - boolean hungUp = false; - if (telephonyService != null) { - try { - hungUp = telephonyService.endCall(); - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); - } - } - interceptPowerKeyDown(!isScreenOn || hungUp); - } else { - if (interceptPowerKeyUp(canceled)) { - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { - if (goHome()) { + if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) { + if (mVolBtnMusicControls && down && (keyCode != KeyEvent.KEYCODE_VOLUME_MUTE)) { + mIsLongPress = false; + handleVolumeLongPress(keyCode); + break; + } else { + if (mVolBtnMusicControls && !down) { + handleVolumeLongPressAbort(); + if (mIsLongPress) { break; } } - if ((mEndcallBehavior - & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { - result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP; + if (!isScreenOn && !mVolumeWakeScreen) { + handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode); } } } - break; + if (isScreenOn || !mVolumeWakeScreen) { + break; + } else if (keyguardActive) { + keyCode = KeyEvent.KEYCODE_POWER; + mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode); + } else { + result |= ACTION_WAKE_UP; + break; + } } case KeyEvent.KEYCODE_POWER: { diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java index b6ffde0..d1651fc 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardStatusViewManager.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2012 The CyanogenMod Project (Weather, Calendar) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +30,12 @@ import libcore.util.MutableInt; import android.content.ContentResolver; import android.content.Context; +import android.content.res.Resources; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.os.Handler; +import android.os.Message; import android.provider.Settings; import android.text.TextUtils; import android.text.format.DateFormat; @@ -36,8 +43,27 @@ import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; +import com.android.internal.R; +import com.android.internal.util.weather.HttpRetriever; +import com.android.internal.util.weather.WeatherInfo; +import com.android.internal.util.weather.WeatherXmlParser; +import com.android.internal.util.weather.YahooPlaceFinder; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.TransportControlView; + +import org.w3c.dom.Document; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; + +import libcore.util.MutableInt; + /*** * Manages a number of views inside of LockScreen layouts. See below for a list of widgets * @@ -71,6 +97,11 @@ class KeyguardStatusViewManager implements OnClickListener { private TextView mOwnerInfoView; private TextView mAlarmStatusView; private TransportControlView mTransportView; + private RelativeLayout mWeatherPanel, mWeatherTempsPanel; + private TextView mWeatherCity, mWeatherCondition, mWeatherLowHigh, mWeatherTemp, mWeatherUpdateTime; + private ImageView mWeatherImage; + private LinearLayout mCalendarPanel; + private TextView mCalendarEventTitle, mCalendarEventDetails; // Top-level container view for above views private View mContainer; @@ -185,6 +216,32 @@ class KeyguardStatusViewManager implements OnClickListener { mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen; mDigitalClock = (DigitalClock) findViewById(R.id.time); + // Weather panel + mWeatherPanel = (RelativeLayout) findViewById(R.id.weather_panel); + mWeatherCity = (TextView) findViewById(R.id.weather_city); + mWeatherCondition = (TextView) findViewById(R.id.weather_condition); + mWeatherImage = (ImageView) findViewById(R.id.weather_image); + mWeatherTemp = (TextView) findViewById(R.id.weather_temp); + mWeatherLowHigh = (TextView) findViewById(R.id.weather_low_high); + mWeatherUpdateTime = (TextView) findViewById(R.id.update_time); + mWeatherTempsPanel = (RelativeLayout) findViewById(R.id.weather_temps_panel); + + // Hide Weather panel view until we know we need to show it. + if (mWeatherPanel != null) { + mWeatherPanel.setVisibility(View.GONE); + mWeatherPanel.setOnClickListener(this); + } + + // Calendar panel + mCalendarPanel = (LinearLayout) findViewById(R.id.calendar_panel); + mCalendarEventTitle = (TextView) findViewById(R.id.calendar_event_title); + mCalendarEventDetails = (TextView) findViewById(R.id.calendar_event_details); + + // Hide calendar panel view until we know we need to show it. + if (mCalendarPanel != null) { + mCalendarPanel.setVisibility(View.GONE); + } + // Hide transport control view until we know we need to show it. if (mTransportView != null) { mTransportView.setVisibility(View.GONE); @@ -204,10 +261,12 @@ class KeyguardStatusViewManager implements OnClickListener { resetStatusInfo(); refreshDate(); updateOwnerInfo(); + refreshWeather(); + refreshCalendar(); // Required to get Marquee to work. final View scrollableViews[] = { mCarrierView, mDateView, mStatus1View, mOwnerInfoView, - mAlarmStatusView }; + mAlarmStatusView, mCalendarEventDetails, mWeatherCity, mWeatherCondition }; for (View v : scrollableViews) { if (v != null) { v.setSelected(true); @@ -215,6 +274,303 @@ class KeyguardStatusViewManager implements OnClickListener { } } + /* + * CyanogenMod Lock screen Weather related functionality + */ + private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u="; + private static WeatherInfo mWeatherInfo = new WeatherInfo(); + private static final int QUERY_WEATHER = 0; + private static final int UPDATE_WEATHER = 1; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case QUERY_WEATHER: + Thread queryWeather = new Thread(new Runnable() { + @Override + public void run() { + LocationManager locationManager = (LocationManager) getContext(). + getSystemService(Context.LOCATION_SERVICE); + final ContentResolver resolver = getContext().getContentResolver(); + boolean useCustomLoc = Settings.System.getInt(resolver, + Settings.System.WEATHER_USE_CUSTOM_LOCATION, 0) == 1; + String customLoc = Settings.System.getString(resolver, + Settings.System.WEATHER_CUSTOM_LOCATION); + String woeid = null; + + // custom location + if (customLoc != null && useCustomLoc) { + try { + woeid = YahooPlaceFinder.GeoCode(getContext().getApplicationContext(), customLoc); + if (DEBUG) + Log.d(TAG, "Yahoo location code for " + customLoc + " is " + woeid); + } catch (Exception e) { + Log.e(TAG, "ERROR: Could not get Location code"); + e.printStackTrace(); + } + // network location + } else { + Criteria crit = new Criteria(); + crit.setAccuracy(Criteria.ACCURACY_COARSE); + String bestProvider = locationManager.getBestProvider(crit, true); + Location loc = null; + if (bestProvider != null) { + loc = locationManager.getLastKnownLocation(bestProvider); + } else { + loc = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER); + } + try { + woeid = YahooPlaceFinder.reverseGeoCode(getContext(), loc.getLatitude(), + loc.getLongitude()); + if (DEBUG) + Log.d(TAG, "Yahoo location code for current geolocation is " + woeid); + } catch (Exception e) { + Log.e(TAG, "ERROR: Could not get Location code"); + e.printStackTrace(); + } + } + Message msg = Message.obtain(); + msg.what = UPDATE_WEATHER; + msg.obj = woeid; + mHandler.sendMessage(msg); + } + }); + queryWeather.setPriority(Thread.MIN_PRIORITY); + queryWeather.start(); + break; + case UPDATE_WEATHER: + String woeid = (String) msg.obj; + if (woeid != null) { + if (DEBUG) { + Log.d(TAG, "Location code is " + woeid); + } + WeatherInfo w = null; + try { + w = parseXml(getDocument(woeid)); + } catch (Exception e) { + } + if (w == null) { + setNoWeatherData(); + } else { + setWeatherData(w); + mWeatherInfo = w; + } + } else { + if (mWeatherInfo.temp.equals(WeatherInfo.NODATA)) { + setNoWeatherData(); + } else { + setWeatherData(mWeatherInfo); + } + } + break; + } + } + }; + + /** + * Reload the weather forecast + */ + private void refreshWeather() { + final ContentResolver resolver = getContext().getContentResolver(); + boolean showWeather = Settings.System.getInt(resolver,Settings.System.LOCKSCREEN_WEATHER, 0) == 1; + + if (showWeather) { + final long interval = Settings.System.getLong(resolver, + Settings.System.WEATHER_UPDATE_INTERVAL, 60); // Default to hourly + boolean manualSync = (interval == 0); + if (!manualSync && (((System.currentTimeMillis() - mWeatherInfo.last_sync) / 60000) >= interval)) { + mHandler.sendEmptyMessage(QUERY_WEATHER); + } else if (manualSync && mWeatherInfo.last_sync == 0) { + setNoWeatherData(); + } else { + setWeatherData(mWeatherInfo); + } + } else { + // Hide the Weather panel view + if (mWeatherPanel != null) { + mWeatherPanel.setVisibility(View.GONE); + } + } + } + + /** + * Display the weather information + * @param w + */ + private void setWeatherData(WeatherInfo w) { + final ContentResolver resolver = getContext().getContentResolver(); + final Resources res = getContext().getResources(); + boolean showLocation = Settings.System.getInt(resolver, + Settings.System.WEATHER_SHOW_LOCATION, 1) == 1; + boolean showTimestamp = Settings.System.getInt(resolver, + Settings.System.WEATHER_SHOW_TIMESTAMP, 1) == 1; + boolean invertLowhigh = Settings.System.getInt(resolver, + Settings.System.WEATHER_INVERT_LOWHIGH, 0) == 1; + + if (mWeatherPanel != null) { + if (mWeatherImage != null) { + String conditionCode = w.condition_code; + String condition_filename = "weather_" + conditionCode; + int resID = res.getIdentifier(condition_filename, "drawable", + getContext().getPackageName()); + + if (DEBUG) + Log.d("Weather", "Condition:" + conditionCode + " ID:" + resID); + + if (resID != 0) { + mWeatherImage.setImageDrawable(res.getDrawable(resID)); + } else { + mWeatherImage.setImageResource(R.drawable.weather_na); + } + } + if (mWeatherCity != null) { + mWeatherCity.setText(w.city); + mWeatherCity.setVisibility(showLocation ? View.VISIBLE : View.GONE); + } + if (mWeatherCondition != null) { + mWeatherCondition.setText(w.condition); + mWeatherCondition.setVisibility(View.VISIBLE); + } + if (mWeatherUpdateTime != null) { + Date lastTime = new Date(mWeatherInfo.last_sync); + String date = DateFormat.getDateFormat(getContext()).format(lastTime); + String time = DateFormat.getTimeFormat(getContext()).format(lastTime); + mWeatherUpdateTime.setText(date + " " + time); + mWeatherUpdateTime.setVisibility(showTimestamp ? View.VISIBLE : View.GONE); + } + if (mWeatherTempsPanel != null && mWeatherTemp != null && mWeatherLowHigh != null) { + mWeatherTemp.setText(w.temp); + mWeatherLowHigh.setText(invertLowhigh ? w.high + " | " + w.low : w.low + " | " + w.high); + mWeatherTempsPanel.setVisibility(View.VISIBLE); + } + + // Show the Weather panel view + mWeatherPanel.setVisibility(View.VISIBLE); + } + } + + /** + * There is no data to display, display 'empty' fields and the + * 'Tap to reload' message + */ + private void setNoWeatherData() { + + if (mWeatherPanel != null) { + if (mWeatherImage != null) { + mWeatherImage.setImageResource(R.drawable.weather_na); + } + if (mWeatherCity != null) { + mWeatherCity.setText(R.string.weather_no_data); + mWeatherCity.setVisibility(View.VISIBLE); + } + if (mWeatherCondition != null) { + mWeatherCondition.setText(R.string.weather_tap_to_refresh); + } + if (mWeatherUpdateTime != null) { + mWeatherUpdateTime.setVisibility(View.GONE); + } + if (mWeatherTempsPanel != null ) { + mWeatherTempsPanel.setVisibility(View.GONE); + } + + // Show the Weather panel view + mWeatherPanel.setVisibility(View.VISIBLE); + } + } + + /** + * Get the weather forecast XML document for a specific location + * @param woeid + * @return + */ + private Document getDocument(String woeid) { + try { + boolean celcius = Settings.System.getInt(getContext().getContentResolver(), + Settings.System.WEATHER_USE_METRIC, 1) == 1; + String urlWithDegreeUnit; + + if (celcius) { + urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "c"; + } else { + urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "f"; + } + + return new HttpRetriever().getDocumentFromURL(String.format(urlWithDegreeUnit, woeid)); + } catch (IOException e) { + Log.e(TAG, "Error querying Yahoo weather"); + } + + return null; + } + + /** + * Parse the weather XML document + * @param wDoc + * @return + */ + private WeatherInfo parseXml(Document wDoc) { + try { + return new WeatherXmlParser(getContext()).parseWeatherResponse(wDoc); + } catch (Exception e) { + Log.e(TAG, "Error parsing Yahoo weather XML document"); + e.printStackTrace(); + } + return null; + } + + /* + * CyanogenMod Lock screen Calendar related functionality + */ + + private void refreshCalendar() { + if (mCalendarPanel != null) { + final ContentResolver resolver = getContext().getContentResolver(); + String[] nextCalendar = null; + boolean visible = false; // Assume we are not showing the view + + // Load the settings + boolean lockCalendar = (Settings.System.getInt(resolver, + Settings.System.LOCKSCREEN_CALENDAR, 0) == 1); + String[] calendars = parseStoredValue(Settings.System.getString( + resolver, Settings.System.LOCKSCREEN_CALENDARS)); + boolean lockCalendarRemindersOnly = (Settings.System.getInt(resolver, + Settings.System.LOCKSCREEN_CALENDAR_REMINDERS_ONLY, 0) == 1); + long lockCalendarLookahead = Settings.System.getLong(resolver, + Settings.System.LOCKSCREEN_CALENDAR_LOOKAHEAD, 10800000); + + if (lockCalendar) { + nextCalendar = mLockPatternUtils.getNextCalendarAlarm(lockCalendarLookahead, + calendars, lockCalendarRemindersOnly); + if (nextCalendar[0] != null && mCalendarEventTitle != null) { + mCalendarEventTitle.setText(nextCalendar[0].toString()); + if (nextCalendar[1] != null && mCalendarEventDetails != null) { + mCalendarEventDetails.setText(nextCalendar[1]); + } + visible = true; + } + } + + mCalendarPanel.setVisibility(visible ? View.VISIBLE : View.GONE); + } + } + + /** + * Split the MultiSelectListPreference string based on a separator of ',' and + * stripping off the start [ and the end ] + * @param val + * @return + */ + private static String[] parseStoredValue(String val) { + if (val == null || val.isEmpty()) + return null; + else { + // Strip off the start [ and the end ] before splitting + val = val.substring(1, val.length() -1); + return (val.split(",")); + } + } + private boolean inWidgetMode() { return mTransportView != null && mTransportView.getVisibility() == View.VISIBLE; } @@ -657,6 +1013,16 @@ class KeyguardStatusViewManager implements OnClickListener { public void onClick(View v) { if (v == mEmergencyCallButton) { mCallback.takeEmergencyCallAction(); + } else if (v == mWeatherPanel) { + // Indicate we are refreshing + if (mWeatherCondition != null) { + mWeatherCondition.setText(R.string.weather_refreshing); + } + + mCallback.pokeWakelock(); + if (!mHandler.hasMessages(QUERY_WEATHER)) { + mHandler.sendEmptyMessage(QUERY_WEATHER); + } } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java index 3de1428..bf43199 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java @@ -25,6 +25,8 @@ import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.Profile; +import android.app.ProfileManager; import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -248,6 +250,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback { private int mUnlockSoundId; private int mLockSoundStreamId; + private ProfileManager mProfileManager; + /** * The volume applied to the lock/unlock sounds. */ @@ -369,6 +373,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback { mWakeAndHandOff.setReferenceCounted(false); mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION)); + mProfileManager = (ProfileManager) context.getSystemService(Context.PROFILE_SERVICE); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); @@ -434,11 +439,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback { mScreenOn = false; if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); - // Lock immediately based on setting if secure (user has a pin/pattern/password). - // This also "locks" the device when not secure to provide easy access to the - // camera while preventing unwanted input. - final boolean lockImmediately = - mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure(); + // Prepare for handling Lock/Slide lock delay and timeout + boolean lockImmediately = false; + final ContentResolver cr = mContext.getContentResolver(); + boolean separateSlideLockTimeoutEnabled = Settings.System.getInt(cr, + Settings.System.SCREEN_LOCK_SLIDE_DELAY_TOGGLE, 0) == 1; + if (mLockPatternUtils.isSecure()) { + // Lock immediately based on setting if secure (user has a pin/pattern/password) + // This is retained as-is to ensue AOSP security integrity is maintained + lockImmediately = mLockPatternUtils.getPowerButtonInstantlyLocks(); + } else { + // Unless a separate slide lock timeout is enabled, this "locks" the device when + // not secure to provide easy access to the camera while preventing unwanted input + lockImmediately = separateSlideLockTimeoutEnabled ? false + : mLockPatternUtils.getPowerButtonInstantlyLocks(); + } if (mExitSecureCallback != null) { if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled"); @@ -457,7 +472,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback { // to enable it a little bit later (i.e, give the user a chance // to turn the screen back on within a certain window without // having to unlock the screen) - final ContentResolver cr = mContext.getContentResolver(); // From DisplaySettings long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, @@ -468,17 +482,33 @@ public class KeyguardViewMediator implements KeyguardViewCallback { Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, KEYGUARD_LOCK_AFTER_DELAY_DEFAULT); + // From CyanogenMod specific Settings + int slideLockTimeoutDelay = (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT ? Settings.System + .getInt(cr, Settings.System.SCREEN_LOCK_SLIDE_TIMEOUT_DELAY, + KEYGUARD_LOCK_AFTER_DELAY_DEFAULT) : Settings.System.getInt(cr, + Settings.System.SCREEN_LOCK_SLIDE_SCREENOFF_DELAY, 0)); + // From DevicePolicyAdmin final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() .getMaximumTimeToLock(null); + if (DEBUG) Log.d(TAG, "Security lock screen timeout delay is " + lockAfterTimeout + + " ms; slide lock screen timeout delay is " + + slideLockTimeoutDelay + + " ms; Separate slide lock delay settings considered: " + + separateSlideLockTimeoutEnabled + + "; Policy timeout is " + + policyTimeout + + " ms"); + long timeout; if (policyTimeout > 0) { // policy in effect. Make sure we don't go beyond policy limit. displayTimeout = Math.max(displayTimeout, 0); // ignore negative values timeout = Math.min(policyTimeout - displayTimeout, lockAfterTimeout); } else { - timeout = lockAfterTimeout; + // Not sure lockAfterTimeout is needed any more but keeping it for AOSP compatibility + timeout = separateSlideLockTimeoutEnabled ? slideLockTimeoutDelay : lockAfterTimeout; } if (timeout <= 0) { @@ -708,6 +738,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback { return; } + // if the current profile has disabled us, don't show + if (!lockedOrMissing + && mProfileManager.getActiveProfile().getScreenLockMode() == Profile.LockMode.DISABLE) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because of profile override"); + return; + } + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); showLocked(); } |
