diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 9b8b1351e2a64..5afe1e8dd4a41 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -73,6 +73,7 @@ #define OEM_SHUTDOWN_ANIMATION_FILE "/oem/media/shutdownanimation.zip" #define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip" #define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip" +#define THEME_SHUTDOWN_ANIMATION_FILE "/data/system/theme/shutdownanimation.zip" #define OEM_BOOT_MUSIC_FILE "/oem/media/boot.wav" #define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav" @@ -408,14 +409,9 @@ status_t BootAnimation::readyToRun() { (access(getAnimationFileName(IMG_ENC), R_OK) == 0) && ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_ENC))) != NULL)) || - ((access(THEME_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(THEME_BOOTANIMATION_FILE)) != NULL)) || + ((access(getAnimationFileName(IMG_THM), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_THM))) != NULL)) || - ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) || - - ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL)) || ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) && ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_DATA))) != NULL)) || @@ -888,12 +884,14 @@ bool BootAnimation::movie() const char *BootAnimation::getAnimationFileName(ImageID image) { - const char *fileName[2][3] = { { OEM_BOOTANIMATION_FILE, + const char *fileName[2][4] = { { OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE, - SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, { + SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, + THEME_BOOTANIMATION_FILE }, { OEM_SHUTDOWN_ANIMATION_FILE, SYSTEM_SHUTDOWN_ANIMATION_FILE, - SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE} }; + SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE, + THEME_SHUTDOWN_ANIMATION_FILE} }; int state; char sku[PROPERTY_VALUE_MAX]; char skusuffix[PATH_MAX]; diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 5bc1e8a45abac..a0f84da031371 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -93,7 +93,7 @@ class BootAnimation : public Thread, public IBinder::DeathRecipient bool readFile(const char* name, String8& outString); bool movie(); - enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2 }; + enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2, IMG_THM = 3 }; const char *getAnimationFileName(ImageID image); const char *getBootRingtoneFileName(ImageID image); void playBackgroundMusic(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index db4e1237d3a4b..c829daa9eed1e 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2048,9 +2048,11 @@ public void setComponentProtectedSetting(ComponentName componentName, boolean ne /** @hide */ @Override - public boolean isComponentProtected(String callingPackage, ComponentName componentName) { + public boolean isComponentProtected(String callingPackage, int callingUid, + ComponentName componentName) { try { - return mPM.isComponentProtected(callingPackage, componentName, mContext.getUserId()); + return mPM.isComponentProtected(callingPackage, callingUid, componentName, + mContext.getUserId()); } catch (RemoteException re) { Log.e(TAG, "Failed to get component protected setting", re); return false; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d443d8071864d..6896c21bcabf2 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2018,6 +2018,11 @@ private File[] ensureDirsExistOrFilter(File[] dirs) { } result.add(dir); } + + // Make sure there is at least one element, let the callers handle that + if (result.size() == 0) { + result.add(null); + } return result.toArray(new File[result.size()]); } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index f78fb47e5f5e9..e749d0a414bb2 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -55,6 +55,9 @@ interface INotificationManager void setPackageVisibilityOverride(String pkg, int uid, int visibility); int getPackageVisibilityOverride(String pkg, int uid); + void setShowNotificationForPackageOnKeyguard(String pkg, int uid, int status); + int getShowNotificationForPackageOnKeyguard(String pkg, int uid); + // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. StatusBarNotification[] getActiveNotifications(String callingPkg); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index d8e01cd0f72ce..8835a090f09fe 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -522,6 +522,21 @@ public class Notification implements Parcelable @Priority public int priority; + /** + * Default. + * Show all notifications from an app on keyguard. + * + * @hide + */ + public static final int SHOW_ALL_NOTI_ON_KEYGUARD = 0x01; + + /** + * Show only notifications from an app which are not ongoing ones. + * + * @hide + */ + public static final int SHOW_NO_ONGOING_NOTI_ON_KEYGUARD = 0x02; + /** * Accent color (an ARGB integer like the constants in {@link android.graphics.Color}) * to be applied by the standard Style templates when presenting this notification. diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 605c006130878..2219e64c9ff9c 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.app.Notification; import android.app.Notification.Builder; import android.content.ComponentName; import android.content.Context; @@ -512,6 +513,16 @@ public ArraySet getPackagesRequestingNotificationPolicyAccess() { return new ArraySet(); } + /** @hide */ + public int getShowNotificationForPackageOnKeyguard(String pkg, int uid) { + INotificationManager service = getService(); + try { + return getService().getShowNotificationForPackageOnKeyguard(pkg, uid); + } catch (RemoteException e) { + return Notification.SHOW_ALL_NOTI_ON_KEYGUARD; + } + } + private Context mContext; private static void checkRequired(String name, Object value) { diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index e2d0537fb1bd6..c98167d255d43 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -576,6 +576,7 @@ private boolean attachThemeAssets(AssetManager assets, ThemeConfig theme) { PackageInfo piTheme = null; PackageInfo piTarget = null; PackageInfo piAndroid = null; + PackageInfo piCm = null; // Some apps run in process of another app (eg keyguard/systemUI) so we must get the // package name from the res tables. The 0th base package name will be the android group. @@ -609,16 +610,20 @@ private boolean attachThemeAssets(AssetManager assets, ThemeConfig theme) { } piAndroid = getPackageManager().getPackageInfo("android", 0, UserHandle.getCallingUserId()); + piCm = getPackageManager().getPackageInfo("cyanogenmod.platform", 0, + UserHandle.getCallingUserId()); } catch (RemoteException e) { } if (piTheme == null || piTheme.applicationInfo == null || piTarget == null || piTarget.applicationInfo == null || piAndroid == null || piAndroid.applicationInfo == null || + piCm == null || piCm.applicationInfo == null || piTheme.mOverlayTargets == null) { return false; } + // Attach themed resources for target String themePackageName = piTheme.packageName; String themePath = piTheme.applicationInfo.publicSourceDir; if (!piTarget.isThemeApk && piTheme.mOverlayTargets.contains(basePackageName)) { @@ -638,6 +643,24 @@ private boolean attachThemeAssets(AssetManager assets, ThemeConfig theme) { } } + // Attach themed resources for cmsdk + if (!piTarget.isThemeApk && !piCm.packageName.equals(basePackageName) && + piTheme.mOverlayTargets.contains(piCm.packageName)) { + String resCachePath= ThemeUtils.getTargetCacheDir(piCm.packageName, + piTheme.packageName); + String prefixPath = ThemeUtils.getOverlayPathToTarget(piCm.packageName); + String targetPackagePath = piCm.applicationInfo.publicSourceDir; + String resApkPath = resCachePath + "/resources.apk"; + String idmapPath = ThemeUtils.getIdmapPath(piCm.packageName, piTheme.packageName); + int cookie = assets.addOverlayPath(idmapPath, themePath, + resApkPath, targetPackagePath, prefixPath); + if (cookie != 0) { + assets.setThemePackageName(themePackageName); + assets.addThemeCookie(cookie); + } + } + + // Attach themed resources for android framework if (!piTarget.isThemeApk && !"android".equals(basePackageName) && piTheme.mOverlayTargets.contains("android")) { String resCachePath= ThemeUtils.getTargetCacheDir(piAndroid.packageName, diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 6d8b5cbe85152..a3329db1817c3 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -521,6 +521,6 @@ interface IPackageManager { int processThemeResources(String themePkgName); /** Protected Apps */ - boolean isComponentProtected(in String callingPackage, in ComponentName componentName, - int userId); + boolean isComponentProtected(in String callingPackage, in int callingUid, + in ComponentName componentName, int userId); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 529d6417cf6e8..8f0500e9b8513 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4564,7 +4564,7 @@ public void onCreated(int moveId, Bundle extras) {} * Return whether or not a specific component is protected * @hide */ - public abstract boolean isComponentProtected(String callingPackage, + public abstract boolean isComponentProtected(String callingPackage, int callingUid, ComponentName componentName); /** diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 6a404e24601a2..7fa04f9ec947d 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -120,6 +120,8 @@ public class Resources { public static final int THEME_APP_PKG_ID = 0x61; /** @hide */ public static final int THEME_ICON_PKG_ID = 0x62; + /** @hide */ + public static final int THEME_CM_PKG_ID = 0x63; /** * The common resource pkg id needs to be less than the THEME_FRAMEWORK_PKG_ID * otherwise aapt will complain and fail diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 961a3f41cd5eb..0107d93c3cfc9 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -1,4 +1,7 @@ /* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,6 +31,7 @@ import android.nfc.INfcTag; import android.nfc.INfcCardEmulation; import android.nfc.INfcUnlockHandler; import android.os.Bundle; +import android.os.IBinder; /** * @hide @@ -37,6 +41,7 @@ interface INfcAdapter INfcTag getNfcTagInterface(); INfcCardEmulation getNfcCardEmulationInterface(); INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg); + IBinder getNfcAdapterVendorInterface(in String vendor); int getState(); boolean disable(boolean saveState); diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 78a9401a2abd9..9abf32565337c 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -1,6 +1,9 @@ /* * Copyright (C) 2015 The Android Open Source Project * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -37,7 +40,7 @@ * * @hide */ -public final class AidGroup implements Parcelable { +public class AidGroup implements Parcelable { /** * The maximum number of AIDs that can be present in any one group. */ @@ -45,9 +48,9 @@ public final class AidGroup implements Parcelable { static final String TAG = "AidGroup"; - final List aids; - final String category; - final String description; + protected List aids; + protected String category; + protected String description; /** * Creates a new AidGroup object. diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java index 8c92288d00479..302c02daa638b 100644 --- a/core/java/android/nfc/tech/MifareClassic.java +++ b/core/java/android/nfc/tech/MifareClassic.java @@ -1,4 +1,6 @@ /* + * Copyright (C) 2015 NXP Semiconductors + * The original Work has been changed by NXP Semiconductors. * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -173,6 +175,10 @@ public MifareClassic(Tag tag) throws RemoteException { mType = TYPE_CLASSIC; mSize = SIZE_4K; break; + case 0x19: + mType = TYPE_CLASSIC; + mSize = SIZE_2K; + break; case 0x28: mType = TYPE_CLASSIC; mSize = SIZE_1K; diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java index 88730f9af3dff..b7fa455e3880c 100644 --- a/core/java/android/nfc/tech/NfcA.java +++ b/core/java/android/nfc/tech/NfcA.java @@ -1,4 +1,6 @@ /* + * Copyright (C) 2015 NXP Semiconductors + * The original Work has been changed by NXP Semiconductors. * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,8 +68,15 @@ public static NfcA get(Tag tag) { /** @hide */ public NfcA(Tag tag) throws RemoteException { super(tag, TagTechnology.NFC_A); - Bundle extras = tag.getTechExtras(TagTechnology.NFC_A); - mSak = extras.getShort(EXTRA_SAK); + Bundle extras; + mSak = 0; + if(tag.hasTech(TagTechnology.MIFARE_CLASSIC)) + { + extras = tag.getTechExtras(TagTechnology.MIFARE_CLASSIC); + mSak = extras.getShort(EXTRA_SAK); + } + extras = tag.getTechExtras(TagTechnology.NFC_A); + mSak |= extras.getShort(EXTRA_SAK); mAtqa = extras.getByteArray(EXTRA_ATQA); } diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 4b6e6c18e0500..a10b1ec362341 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -335,22 +335,27 @@ public static void installPackage(Context context, File packageFile) throws IOException { String filename = packageFile.getCanonicalPath(); - FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE); - try { - uncryptFile.write(filename + "\n"); - } finally { - uncryptFile.close(); - } - // UNCRYPT_FILE needs to be readable by system server on bootup. - if (!UNCRYPT_FILE.setReadable(true, false)) { - Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath()); - } - Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); + final String cryptoStatus = SystemProperties.get("ro.crypto.state", "unsupported"); + final boolean isEncrypted = "encrypted".equalsIgnoreCase(cryptoStatus); - // If the package is on the /data partition, write the block map file - // into COMMAND_FILE instead. - if (filename.startsWith("/data/")) { - filename = "@/cache/recovery/block.map"; + if (isEncrypted) { + FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE); + try { + uncryptFile.write(filename + "\n"); + } finally { + uncryptFile.close(); + } + // UNCRYPT_FILE needs to be readable by system server on bootup. + if (!UNCRYPT_FILE.setReadable(true, false)) { + Log.e(TAG, "Error setting readable for " + UNCRYPT_FILE.getCanonicalPath()); + } + Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); + + // If the package is on the /data partition, write the block map file + // into COMMAND_FILE instead. + if (filename.startsWith("/data/")) { + filename = "@/cache/recovery/block.map"; + } } final String filenameArg = "--update_package=" + filename; diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 72f5de57ab196..e5f71a00f8a54 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -412,10 +412,11 @@ public void onReceive(Context context, Intent intent) { int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); updateVolumeSlider(streamType, streamValue); } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { + final int oldRingerMode = mRingerMode; if (mNotificationOrRing) { mRingerMode = mAudioManager.getRingerModeInternal(); } - if (mAffectedByRingerMode) { + if (mAffectedByRingerMode && oldRingerMode != mRingerMode) { updateSlider(); } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5045b1ad67ef0..3ab16fe7a39cf 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1509,7 +1509,6 @@ public static interface Validator { // At one time in System, then Global, but now back in Secure MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS); - MOVED_TO_SECURE.add(System.DEV_FORCE_SHOW_NAVBAR); MOVED_TO_SECURE.add(System.KEYBOARD_BRIGHTNESS); MOVED_TO_SECURE.add(System.BUTTON_BRIGHTNESS); MOVED_TO_SECURE.add(System.BUTTON_BACKLIGHT_TIMEOUT); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 527d7e51c3e32..e0c9d596cc9ab 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -416,6 +416,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public static final int FLAG_WINDOW_IS_OBSCURED = 0x1; + /** + * This flag indicates that the window that received this motion event is partly + * or wholly obscured by another visible window above it. This flag is set to true + * even if the event did not directly pass through the obscured area. + * A security sensitive application can check this flag to identify situations in which + * a malicious application may have covered up part of its content for the purpose + * of misleading the user or hijacking touches. An appropriate response might be + * to drop the suspect touches or to take additional precautions to confirm the user's + * actual intent. + * + * Unlike FLAG_WINDOW_IS_OBSCURED, this is actually true. + * @hide + */ + public static final int FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2; + /** * Private flag that indicates when the system has detected that this motion event * may be inconsistent with respect to the sequence of previously delivered motion events, diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 3616622ed5bff..65577f0a8751b 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -869,9 +869,12 @@ public void setFlags(int flags, int mask) { } private void setPrivateFlags(int flags, int mask) { - if ((flags & mask & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0){ - mContext.enforceCallingOrSelfPermission("android.permission.PREVENT_POWER_KEY", - "No permission to prevent power key"); + int preventFlags = WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY | + WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS; + + if ((flags & mask & preventFlags) != 0) { + mContext.enforceCallingOrSelfPermission("android.permission.PREVENT_SYSTEM_KEYS", + "No permission to prevent system key"); } final WindowManager.LayoutParams attrs = getAttributes(); attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1125b4455c518..36f593e44c48a 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1154,7 +1154,13 @@ public static class LayoutParams extends ViewGroup.LayoutParams public static final int PRIVATE_FLAG_WAS_NOT_FULLSCREEN = 0x02000000; /** - * Window flag: Overrides default power key behavior + * Window flag: Overrides default system key behavior. + * {@hide} + */ + public static final int PRIVATE_FLAG_PREVENT_SYSTEM_KEYS = 0x10000000; + + /** + * Window flag: Overrides default system key behavior. * {@hide} */ public static final int PRIVATE_FLAG_PREVENT_POWER_KEY = 0x20000000; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 00e250bce3de0..4c3cc4d99d330 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -91,7 +91,7 @@ public class ResolverActivity extends Activity { private ResolveListAdapter mAdapter; private PackageManager mPm; private boolean mSafeForwardingMode; - private boolean mAlwaysUseOption; + /*package*/ boolean mAlwaysUseOption; private AbsListView mAdapterView; private ViewGroup mFilteredItemContainer; private Button mAlwaysButton; @@ -1571,7 +1571,7 @@ protected DisplayResolveInfo getDisplayResolveInfo(int index) { return mDisplayList.get(index); } - public final View getView(int position, View convertView, ViewGroup parent) { + public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { view = createView(parent); diff --git a/core/java/com/android/internal/app/ResolverProxy.java b/core/java/com/android/internal/app/ResolverProxy.java new file mode 100644 index 0000000000000..f59fd11f45718 --- /dev/null +++ b/core/java/com/android/internal/app/ResolverProxy.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import java.util.List; +import android.content.pm.ResolveInfo; +import android.content.Context; +import android.content.Intent; +import android.widget.AbsListView; +import android.app.VoiceInteractor.PickOptionRequest.Option; +import com.android.internal.app.ResolverActivity.TargetInfo; + +/** Relax access modifiers on key ResolverActivity extension methods to allow + them to be overridden from a different package/classloader. + Used by CMResolver */ +public class ResolverProxy extends ResolverActivity { + private static final String TAG = "ResolverProxy"; + + /** If the superclass may set up adapter entries after onCreate completes, + This method should be overridden to do nothing, and + sendVoiceChoicesIfNeeded should be called once the adapter setup is + complete. */ + @Override + protected void onSetupVoiceInteraction() { + super.onSetupVoiceInteraction(); + } + + /** see onSetupVoiceInteraction */ + @Override + protected void sendVoiceChoicesIfNeeded() { + super.sendVoiceChoicesIfNeeded(); + } + + @Override + protected int getLayoutResource() { + return super.getLayoutResource(); + } + + @Override + protected void bindProfileView() { + super.bindProfileView(); + } + + @Override + protected Option optionForChooserTarget(TargetInfo target, int index) { + return super.optionForChooserTarget(target, index); + } + + @Override + protected boolean shouldGetActivityMetadata() { + return super.shouldGetActivityMetadata(); + } + + @Override + protected boolean shouldAutoLaunchSingleChoice(TargetInfo target) { + return super.shouldAutoLaunchSingleChoice(target); + } + + @Override + protected void showAppDetails(ResolveInfo ri) { + super.showAppDetails(ri); + } + + @Override + void startSelected(int which, boolean always, boolean filtered) { + super.startSelected(which, always, filtered); + } + + @Override + protected void onActivityStarted(TargetInfo cti) { + super.onActivityStarted(cti); + } + + @Override + protected boolean configureContentView( + List payloadIntents, Intent[] initialIntents, + List rList, boolean alwaysUseOption) { + return super.configureContentView( + payloadIntents, initialIntents, rList, alwaysUseOption); + } + + @Override + protected void onPrepareAdapterView( + AbsListView adapterView, ResolveListAdapter adapter, boolean alwaysUseOption) { + super.onPrepareAdapterView(adapterView, adapter, alwaysUseOption); + } + + /** subclasses cannot override this because ResolveListAdapter is an inaccessible + type. Override createProxyAdapter(...) instead */ + @Override + ResolveListAdapter createAdapter(Context context, List payloadIntents, + Intent[] initialIntents, List rList, int launchedFromUid, + boolean filterLastUsed) { + ProxyListAdapter adapter = createProxyAdapter( + context, payloadIntents, initialIntents, rList, launchedFromUid, filterLastUsed); + return (adapter != null) + ? adapter + : super.createAdapter(context, payloadIntents, initialIntents, + rList, launchedFromUid, filterLastUsed); + } + + /** Subclasses should override this instead of createAdapter to avoid issues + with ResolveListAdapter being an inaccessible type */ + protected ProxyListAdapter createProxyAdapter(Context context, List payloadIntents, + Intent[] initialIntents, List rList, int launchedFromUid, + boolean filterLastUsed) { + return null; + } + + protected void setAlwaysUseOption(boolean alwaysUse) { + mAlwaysUseOption = alwaysUse; + } + + /** Provides a visible type for exending ResolveListAdapter - fortunately the key + methods one would need to override in ResolveListAdapter are all public or protected */ + public class ProxyListAdapter extends ResolveListAdapter { + public ProxyListAdapter( + Context context, List payloadIntents, Intent[] initialIntents, + List rList, int launchedFromUid, boolean filterLastUsed) { + super(context, payloadIntents, initialIntents, rList, launchedFromUid, filterLastUsed); + } + + /** complements getDisplayInfoCount and getDisplayInfoAt */ + public TargetInfo removeDisplayInfoAt(int index) { + if (index >= 0 && index < mDisplayList.size()) { + return mDisplayList.remove(index); + } else { + return null; + } + } + } +} diff --git a/core/java/com/android/internal/util/cm/SpamFilter.java b/core/java/com/android/internal/util/cm/SpamFilter.java index 9de44896fa956..c261009de0d34 100644 --- a/core/java/com/android/internal/util/cm/SpamFilter.java +++ b/core/java/com/android/internal/util/cm/SpamFilter.java @@ -46,10 +46,21 @@ public static String getNormalizedNotificationContent(Notification notification) } public static String getNotificationContent(Notification notification) { + CharSequence notificationTitle = getNotificationTitle(notification); + CharSequence notificationMessage = getNotificationMessage(notification); + return notificationTitle + "\n" + notificationMessage; + } + + private static CharSequence getNotificationTitle(Notification notification) { Bundle extras = notification.extras; String titleExtra = extras.containsKey(Notification.EXTRA_TITLE_BIG) ? Notification.EXTRA_TITLE_BIG : Notification.EXTRA_TITLE; CharSequence notificationTitle = extras.getCharSequence(titleExtra); + return notificationTitle; + } + + private static CharSequence getNotificationMessage(Notification notification) { + Bundle extras = notification.extras; CharSequence notificationMessage = extras.getCharSequence(Notification.EXTRA_TEXT); if (TextUtils.isEmpty(notificationMessage)) { @@ -60,6 +71,12 @@ public static String getNotificationContent(Notification notification) { notificationMessage = TextUtils.join("\n", inboxLines); } } - return notificationTitle + "\n" + notificationMessage; + return notificationMessage; + } + + public static boolean hasFilterableContent(Notification notification) { + CharSequence notificationTitle = getNotificationTitle(notification); + CharSequence notificationMessage = getNotificationMessage(notification); + return !(TextUtils.isEmpty(notificationTitle) && TextUtils.isEmpty(notificationMessage)); } } diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index 92d5aea18a525..6103ebc257efb 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -97,6 +97,7 @@ private void logBootEvents(Context ctx) throws IOException { final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE); final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE); final String headers = new StringBuilder(512) + .append("CM Version: ").append(SystemProperties.get("ro.cm.version")).append("\n") .append("Build: ").append(Build.FINGERPRINT).append("\n") .append("Hardware: ").append(Build.BOARD).append("\n") .append("Revision: ") diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index a282a4427078f..91b3278c2e2b7 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -154,11 +154,6 @@ static struct { jmethodID postDynPolicyEventFromNative; } gDynPolicyEventHandlerMethods; -static struct { - jmethodID postEffectSessionEventFromNative; -} gEffectSessionEventHandlerMethods; - - static Mutex gLock; enum AudioError { @@ -391,25 +386,6 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) } -static void -android_media_AudioSystem_effect_session_callback(int event, audio_stream_type_t stream, - audio_unique_id_t sessionId, audio_output_flags_t flags, - audio_channel_mask_t channelMask, uid_t uid, bool added) -{ - JNIEnv *env = AndroidRuntime::getJNIEnv(); - if (env == NULL) { - return; - } - - jclass clazz = env->FindClass(kClassPathName); - - env->CallStaticVoidMethod(clazz, gEffectSessionEventHandlerMethods.postEffectSessionEventFromNative, - event, stream, sessionId, flags, channelMask, uid, added); - - env->DeleteLocalRef(clazz); - -} - static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name) { @@ -1511,12 +1487,6 @@ android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz) AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback); } -static void -android_media_AudioSystem_registerEffectSessionCallback(JNIEnv *env, jobject thiz) -{ - AudioSystem::setEffectSessionCallback(android_media_AudioSystem_effect_session_callback); -} - static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, @@ -1689,8 +1659,6 @@ static JNINativeMethod gMethods[] = { (void *)android_media_AudioSystem_registerPolicyMixes}, {"native_register_dynamic_policy_callback", "()V", (void *)android_media_AudioSystem_registerDynPolicyCallback}, - {"native_register_effect_session_callback", "()V", - (void *)android_media_AudioSystem_registerEffectSessionCallback}, {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady}, }; @@ -1798,10 +1766,6 @@ int register_android_media_AudioSystem(JNIEnv *env) GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); - gEffectSessionEventHandlerMethods.postEffectSessionEventFromNative = - GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), - "effectSessionCallbackFromNative", "(IIIIIIZ)V"); - jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule", diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 50a4b38e57f0a..ea0e39c2aba30 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1239,10 +1239,10 @@ - - @@ -2815,7 +2815,7 @@ android:label="@string/managed_profile_label"> @@ -2856,14 +2856,14 @@ @@ -2871,19 +2871,19 @@ @@ -2903,7 +2903,7 @@ diff --git a/core/res/res/values-ast-rES/cm_strings.xml b/core/res/res/values-ast-rES/cm_strings.xml index 9c65ae053620c..f72129aac27ba 100644 --- a/core/res/res/values-ast-rES/cm_strings.xml +++ b/core/res/res/values-ast-rES/cm_strings.xml @@ -135,7 +135,9 @@ executase al aniciu notificaciones emerxentes cambiar Bluetooth + conmutar datos móviles cambiar NFC + alternar Wi-Fi remanar volume de l\'alarma remanar el volume de soníu remanar el volume del Bluetooth @@ -148,6 +150,21 @@ remanar el volume de la llamada escribir un mensaxe MMS escribir un mensaxe SMS + usar buelga + amestar corréu de voz + estáu d\'accesu al teléfonu + escaniar rede Wi-Fi + camudar el fondu + usar cadarma d\'asistencia + facer una captura + usar sensores corporales + lleer tresmisiones celulares + simular la llocalización + lleer almacenamientu esternu + escribir almacenamientu esternu + prender pantalla + consiguir cuentes del preséu + camudar estáu del Wi-Fi obtener accesu root @@ -158,10 +175,16 @@ + Bloquióse\'l llanzamientu de l\'actividá + %1$s protexóse pa nun llanciase. Calca p\'autenticate y llanciar l\'aplicación. + Batería cargada ensembre + Desconeuta\'l preséu del cargador p\'ameyorar la vida útil de la batería. + Les tarxetes SIM camudaron + Toca p\'afitar les preferencies por defeutu de la tarxeta SIM diff --git a/core/res/res/values-ast-rES/strings.xml b/core/res/res/values-ast-rES/strings.xml index 93e73645584f7..6ded8e322357a 100644 --- a/core/res/res/values-ast-rES/strings.xml +++ b/core/res/res/values-ast-rES/strings.xml @@ -35,6 +35,7 @@ to display a size in kilobytes, megabytes, or other size units. Some languages (like French) will want to add a space between the placeholders. --> + %1$s%2$s %1$d díes @@ -211,15 +212,22 @@ Banner d\'itinerancia desactiváu Guetando serviciu + Llamaes Wifi + %s + %s + Non + Rede Wi-Fi preferida + Rede móvil preferida + Namái Wi-Fi + El to perfil de trabayu yá nun ta disponible nesti preséu. Timbre activáu + Anovamientu del sistema Android + Preparando l\'anovamientu\u2026 + Procesando\'l paquete d\'anovamientu\u2026 + Reaniciando\u2026 + Reafitar a axustes de fábrica + Reiniciando\u2026 Apagando\u2026 Axustes + Asistencia + Asistente voz Bloquiar agora Sistema Android + Personal Trabayu + Contautos + acceder a los contautos + Llocalización + accesu a la llocalización d\'esti preséu Calendariu + acceder al calendariu SMS + unviar y ver mensaxes SMS Almacenamientu + acceder a les semeyes, conteníu multimedia y los ficheros del preséu Micrófonu @@ -451,11 +476,15 @@ Cámara + facer semeyes y grabar vídeos Teléfonu + facer y xestionar llamaes telefóniques + Sensores corporales + acceder a los datos del sensor tocante a los tos signos vitales Recuperar el conteníu de la ventana @@ -511,11 +540,17 @@ lleer mensaxes de difusión móvil + Permite a l\'app lleer + los mensaxes de difusión móvil que recibe\'l preséu. En dalgunas llocalizaciones, + les alertes de difusión móvil únviense pa informar situaciones d\'emerxencia. + Les aplicaciones malicioses puen afeutar el rindimientu o funcionamientu del + preséu cuando se recibe un mensaxe de difusión móvil d\'emerxencia. lleer feeds a los que ta soscritu l\'usuariu Permite que l\'aplicación obtenga detalles sobre los feeds sincronizaos anguaño. + unviar y ver mensaxes SMS Permite que l\'aplicación unvie mensaxes SMS, lo que pue xenerar cargos inesperaos. Les aplicaciones malintencionaes puen causate gastos imprevistos al unviar mensaxes ensin la to confirmación. @@ -536,6 +571,7 @@ + Permite que les apps configuren los perfiles de propietarios y el propietariu del preséu. reorganizar aplicaciones n\'execución @@ -659,6 +695,7 @@ Permite que l\'aplicación faiga llamaes ensin intervención del usuariu, lo que pue dar llugar a llamaes o cargos inesperaos. Les aplicaciones nun puen usar este serviciu pa facer llamaes a númberos d\'emerxencia, pero les aplicaciones malintencionaes puen causate gastos imprevistos al facer llamaes ensin la to confirmación. + acceder al serviciu IMS pa facer llamaes consultar la identidá y l\'estáu del teléfonu @@ -774,6 +811,7 @@ + Vuelvi intentalo. @@ -878,13 +916,18 @@ + enllazar con servicios de fornidores + Permite al propietariu enllazar con servicios de fornidores. Les aplicaciones normales nun tendríen de precisar esti permisu. + Accesu a la función Nun molestar + Permite que l\'app llea y modifique la configuración de la función Nun molestar. Establecimientu de regles de contraseña + Permite remanar la llonxitú y los caráuteres permitíos nes contraseñes y los PIN pal bloquéu de pantalla. Control d\'intentos de bloquéu de pantalla @@ -906,14 +949,22 @@ Desaniciar los datos del teléfonu ensin avisar, reafitando los datos de fábrica + Desaniciar los datos del usuariu + Permite desaniciar los datos del usuariu nesta tablet ensin avisu previu. + Permite desaniciar los datos del usuariu nesta TV ensin avisu previu. + Permite desaniciar los datos del usuariu nesti tfnu ensin avisu previu. Definir el sirvidor proxy global + Configura\'l proxy global de preséu que va usase + mentanto s\'habilita la política. Namái el propietariu del preséu pue configurar el proxy global. + Config. vencimientu contraseña + Permite modificar la frecuencia cola que se camuda la contraseña, el PIN o\'l patrón de bloquéu de pantalla. Cifráu d\'almacenamientu @@ -923,7 +974,9 @@ Evitar l\'usu de les cámares del preséu + Deshabilitar func. del bloquéu + Evita l\'usu de dalgunes funciones de bloquéu de pantalla. @@ -1161,6 +1214,7 @@ Dibuxar patrón de desbloquéu + Emerxencia Volver a llamada @@ -2014,11 +2068,15 @@ Aceutar + USB pa tresferir ficheros + USB pa tresferir semeyes + USB pa MIDI Coneutáu a un accesoriu USB + Toca pa más opciones. Depuración USB coneutada @@ -2046,42 +2104,77 @@ candidatos + Tresnando\'l mediu %s + Verificando fallos + Deteutóse %s nuevu + Pa tresferir semeyes y conteníu multimedia + %s ta dañáu + %s ta dañáu. Toca pa iguar. + %s non compatible + El preséu nun ye compatible con %s. Toca la pantalla pa configuralu nun formatu compatible. + Desmontóse %s de mou inesperáu. + Pa evitar perda de datos, desactiva\'l preséu %s enantes d\'estrayelu + Estráxose %s + %s estrayíu; inxerta ún nuevu + Espulsando\'l mediu %s\u2026 + Nun estrayer + Configurar + Espulsar + Esplorar + Nun s\'atopa %s + Volver a inxertar preséu + Moviendo %s + Moviendo datos + Tresferencia completa + Tresfiriéronse los datos a %s + Nun pudieron tresferise datos + Los datos quedaron na llocalización orixinal + Estrayíu + Espulsáu Comprobando\u2026 + Llistu + Namái-llectura + Nun s\'estraxo de mou seguru + Toyíu + Non compatible + Espulsando\u2026 + Formatiando\u2026 + Non inxertáu Nun s\'atopó nenguna actividá coincidente. @@ -2092,6 +2185,7 @@ Permite qu\'una aplicación consulte sesiones d\'instalación pa ver detalles tocante a instalaciones de paquetes activos. + Permite qu\'una app solicite la instalación de paquetes. Toca dos vegaes p\'acceder al control de zoom. Amenorgar año + Mes anterior + Mes siguiente Alt @@ -2338,8 +2434,11 @@ Tarxeta SD + Tarxeta SD de %s + Unidá USB + Unidá USB de %s Almacenamientu USB @@ -2788,8 +2887,11 @@ Volver a intentalo dempués + Visualización en pantalla completa + Pa salir, esliza\'l deu hacia abaxo dende la parte superior. + Atalántolo Fecho + sans-serif-medium + sans-serif-medium + sans-serif-medium Pa desactivar esta pantalla, caltén primíos al empar los botones de retrocesu y Visión xeneral. Pa desactivar esta pantalla, caltén primíu\'l botón Visión xeneral. + L\'app ta fixada: nun se permite desfixala nesti preséu. Pantalla fixada @@ -2843,29 +2949,51 @@ Solicitar contraseña pa desactivar + Instaláu pol alministrador + Anováu pol alministrador + Desaniciáu pol alministrador + + Mentanto 1 min (hasta la(les) %2$s) + Mentanto %1$d mins (hasta la(les) %2$s) + + + Mentanto 1 hr (hasta la(les) %2$s) + Mentanto %1$d hrs (hasta la(les) %2$s) + Mientres un minutu Mientres %d minutos + + Mentanto 1 min + Mentanto %d mins + Mientres una hora Mientres %d hores + + Mentanto 1 hr + Mentanto %d hrs + + Hasta les %1$s hores (próxima alarma) + Hasta que lo desactives + Hasta que desactives Nun molestar diff --git a/core/res/res/values-be/cm_strings.xml b/core/res/res/values-be/cm_strings.xml index 8a524bc39dc6b..5e73c3983be61 100644 --- a/core/res/res/values-be/cm_strings.xml +++ b/core/res/res/values-be/cm_strings.xml @@ -135,6 +135,7 @@ прызначыць запуск пры ўлучэнні прылады адлюстроўваць усплывальныя паведамленні пераключыць стан Bluetooth + пераключыць стан сотавай сеткі пераключыць стан модуля NFC пераключыць стан Wi-Fi атрымаць кіраванне гучнасцю будзільніка @@ -178,6 +179,8 @@ Запуск дадатку забаронены Дадатак %1$s заблакаваны на запуск. Націсні, каб увесці паролль і запусціць дадатак. + Батарэя цалкам зараджана + Адлучы зарадную прыладу каб павялічыць тэрмін жыцця батарэі. Абнуленне статыстыкі батарэі @@ -185,4 +188,6 @@ whether they want to allow the application to do this. --> Дазволіць дадатку чысціць дадзеныя пра выкарыстанне акумулятарнай батарэі прылады. + SIM-картка змянілася + Націсні, каб усталяваць параметры па змаўчанні diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 2172d90ee3ce4..94637b60d9079 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -20,7 +20,7 @@ --> - Б + Біт КБ @@ -37,50 +37,84 @@ the placeholders. --> %1$s%2$s + %1$d содняў + %1$d содні + %2$d гадзінаў + %1$d содні + %2$dгадзін + %1$d гадзінаў + %1$d гадзін + %2$d хвілін + %1$d г + %2$d хв + %1$d хвілінаў + %1$d хвіліна + %1$d хвілін + %2$d сэкунд + %1$d хвілін + %2$d сэкунда + %1$d сэкундаў + %1$d сэкунд + <Без назвы> + (Няма нумару тэлефону) + Невядомы + Галасавая пошта + MSISDN1 + Праблема падчас падлучэньня, магчыма памылка коду MMI. + Абмежаваньне: выкарыстоўваюцца толькі дазволеныя нумары. + Служба была ўключана. + Служба была ўключана для: + Служба была адключана. + Рэгістрацыя прайшла пасьпяхова. + Пасьпяхова выдалена. Памылковы пароль. Запыт MMI завершаны. + Памылка: неабходны стары PIN-код. Уведзены памылковы PUK-код. + PIN-коды ня супадаюць. - Увядзіце PIN-код (ад 4 да 8 лічбаў). + PIN-код (ад 4 да 8 лічбаў). - Увядзіце PUK-код з 8 лічбаў ці больш. + PUK-код ад 8 лічбаў і больш. - Для разблакавання SIM-карткі увядзіце код PUK2. + SIM-картка заблакавана PUK-кодам. Неабходны PUK-код, каб разблакаваць картку. + Для разблакаваньня SIM-карткі неабходны PUK2-код. + Памылка. Падлучы блакаваньне SIM-карткі ці карткі RUIM. У вас засталася %d спроба перад тым, як SIM-картка будзе заблакавана. @@ -88,18 +122,31 @@ У вас засталася %d спробы перад тым, як SIM-картка будзе заблакавана. + IMEI + MEID + Уваходны выклік + Зыходны выклік + Абмежаваньне ідэнтыфікатару падлучанай лініі + Пераадрасаваньне выклікаў + Чаканьне выкліку Забарона выклікаў + Зьмена пароля + Зьмена PIN-коду + Бягучы нумар выкліку + Нумар выкліку абмежаваны + Трохбаковы выклік + Адмова ад непажаданых выклікаў @@ -268,6 +315,7 @@ + Рэжым лёту diff --git a/core/res/res/values-bg/cm_strings.xml b/core/res/res/values-bg/cm_strings.xml index 2614572f7e427..8b94d248ebad4 100644 --- a/core/res/res/values-bg/cm_strings.xml +++ b/core/res/res/values-bg/cm_strings.xml @@ -183,7 +183,7 @@ Изключете зарядното устройството за да удължите живота на батерията. - Статистиката на батерията ще бъде нулирана + Нулиране статистиката на батерията Позволява заявление да рестартирате текущите данни за използването на ниско ниво на батерията. diff --git a/core/res/res/values-en-rGB/cm_strings.xml b/core/res/res/values-en-rGB/cm_strings.xml index 2ce9b8bbaccd9..34be26cabeebe 100644 --- a/core/res/res/values-en-rGB/cm_strings.xml +++ b/core/res/res/values-en-rGB/cm_strings.xml @@ -55,6 +55,7 @@ + toggle mobile data diff --git a/core/res/res/values-ja/cm_strings.xml b/core/res/res/values-ja/cm_strings.xml index 511f5213dd9fa..952a149a70a89 100644 --- a/core/res/res/values-ja/cm_strings.xml +++ b/core/res/res/values-ja/cm_strings.xml @@ -135,7 +135,7 @@ 起動時の実行 トーストメッセージの表示 Bluetoothの切り替え - データ通信の切り替え + モバイルデータの切り替え NFCの切り替え Wi-Fiの切り替え アラームの音量の制御 @@ -188,4 +188,6 @@ whether they want to allow the application to do this. --> 現在の電池消費量の低レベルデータをリセットすることをアプリに許可します。 + SIMカードが変更されました + タップしてSIMカードのデフォルトの設定をする diff --git a/core/res/res/values-ko/cm_strings.xml b/core/res/res/values-ko/cm_strings.xml index 697df4b85ec63..5554d77840ec9 100644 --- a/core/res/res/values-ko/cm_strings.xml +++ b/core/res/res/values-ko/cm_strings.xml @@ -188,4 +188,6 @@ whether they want to allow the application to do this. --> 앱이 현재의 배터리 사용 데이터를 초기화할 수 있도록 허용합니다. + SIM 카드가 변경되었습니다 + 탭하여 SIM 카드를 재설정 diff --git a/core/res/res/values/cm_styles.xml b/core/res/res/values/cm_styles.xml new file mode 100644 index 0000000000000..1d0de05a9e131 --- /dev/null +++ b/core/res/res/values/cm_styles.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 03ea73c262da7..a7efccd214d2d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -531,7 +531,7 @@ 8dp - 7dp + 3dp 3dp diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index e606156758f59..06c29577d755e 100755 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2013-14 The Android Open Source Project + * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,43 +17,47 @@ package com.android.systemui; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.BatteryStateRegistar; - import android.animation.ArgbEvaluator; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.content.res.Resources; +import android.content.res.ThemeConfig; import android.content.res.TypedArray; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.Typeface; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.os.BatteryManager; import android.os.Bundle; import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; import android.view.View; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryStateRegistar; + +import org.cyanogenmod.graphics.drawable.StopMotionVectorDrawable; + public class BatteryMeterView extends View implements DemoMode, BatteryController.BatteryStateChangeCallback { public static final String TAG = BatteryMeterView.class.getSimpleName(); public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST"; - private static final int FULL = 96; - - private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction - private final int[] mColors; protected boolean mShowPercent = true; - private float mButtonHeightFraction; - private float mSubpixelSmoothingLeft; - private float mSubpixelSmoothingRight; public enum BatteryMeterMode { BATTERY_METER_GONE, @@ -66,14 +71,9 @@ public enum BatteryMeterMode { private int mWidth; private String mWarningString; private final int mCriticalLevel; - private final int mFrameColor; private boolean mAnimationsEnabled; - private final Path mShapePath = new Path(); - private final Path mClipPath = new Path(); - private final Path mTextPath = new Path(); - private BatteryStateRegistar mBatteryStateRegistar; private BatteryController mBatteryController; private boolean mPowerSaveEnabled; @@ -94,6 +94,9 @@ public enum BatteryMeterMode { private BatteryMeterDrawable mBatteryMeterDrawable; private int mIconTint = Color.WHITE; + private int mCurrentBackgroundColor = 0; + private int mCurrentFillColor = 0; + protected class BatteryTracker extends BroadcastReceiver { public static final int UNKNOWN_LEVEL = -1; @@ -225,8 +228,6 @@ public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { final Resources res = context.getResources(); TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView, defStyle, 0); - mFrameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor, - res.getColor(R.color.batterymeter_frame_color)); TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels); TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values); @@ -242,12 +243,6 @@ public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol); mCriticalLevel = getContext().getResources().getInteger( com.android.internal.R.integer.config_criticalBatteryWarningLevel); - mButtonHeightFraction = context.getResources().getFraction( - R.fraction.battery_button_height_fraction, 1, 1); - mSubpixelSmoothingLeft = context.getResources().getFraction( - R.fraction.battery_subpixel_smoothing_left, 1, 1); - mSubpixelSmoothingRight = context.getResources().getFraction( - R.fraction.battery_subpixel_smoothing_right, 1, 1); mDarkModeBackgroundColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_background); @@ -260,17 +255,13 @@ public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { } protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) { - Resources res = mContext.getResources(); + Resources res = getResources(); switch (mode) { - case BATTERY_METER_CIRCLE: - return new CircleBatteryMeterDrawable(res); - case BATTERY_METER_ICON_LANDSCAPE: - return new NormalBatteryMeterDrawable(res, true); case BATTERY_METER_TEXT: case BATTERY_METER_GONE: return null; default: - return new NormalBatteryMeterDrawable(res, false); + return new AllInOneBatteryMeterDrawable(res, mode); } } @@ -279,13 +270,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); - if (mMeterMode == BatteryMeterMode.BATTERY_METER_CIRCLE) { - height += (CircleBatteryMeterDrawable.STROKE_WITH / 3); - width = height; - } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) { + if (mMeterMode == BatteryMeterMode.BATTERY_METER_TEXT) { onSizeChanged(width, height, 0, 0); // Force a size changed event - } else if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) { - width = (int)(height * 1.2f); } setMeasuredDimension(width, height); @@ -378,11 +364,6 @@ public void setMode(BatteryMeterMode mode) { mBatteryMeterDrawable.onDispose(); } mBatteryMeterDrawable = createBatteryMeterDrawable(mode); - if (mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_PORTRAIT || - mMeterMode == BatteryMeterMode.BATTERY_METER_ICON_LANDSCAPE) { - ((NormalBatteryMeterDrawable)mBatteryMeterDrawable).loadBoltPoints( - mContext.getResources()); - } if (tracker.present) { setVisibility(View.VISIBLE); requestLayout(); @@ -394,7 +375,6 @@ public void setMode(BatteryMeterMode mode) { } public int getColorForLevel(int percent) { - // If we are in power save mode, always use the normal color. if (mPowerSaveEnabled) { return mColors[mColors.length-1]; @@ -418,9 +398,9 @@ public int getColorForLevel(int percent) { public void setDarkIntensity(float darkIntensity) { if (mBatteryMeterDrawable != null) { - int backgroundColor = getBackgroundColor(darkIntensity); - int fillColor = getFillColor(darkIntensity); - mBatteryMeterDrawable.setDarkIntensity(backgroundColor, fillColor); + mCurrentBackgroundColor = getBackgroundColor(darkIntensity); + mCurrentFillColor = getFillColor(darkIntensity); + mBatteryMeterDrawable.setDarkIntensity(mCurrentBackgroundColor, mCurrentFillColor); } } @@ -482,253 +462,83 @@ protected interface BatteryMeterDrawable { void setDarkIntensity(int backgroundColor, int fillColor); } - protected class NormalBatteryMeterDrawable implements BatteryMeterDrawable { + protected class AllInOneBatteryMeterDrawable implements BatteryMeterDrawable { private static final boolean SINGLE_DIGIT_PERCENT = false; private static final boolean SHOW_100_PERCENT = false; private boolean mDisposed; - protected final boolean mHorizontal; + private boolean mIsAnimating; // stores charge-animation status to remove callbacks + + private float mTextX, mTextY; // precalculated position for drawText() to appear centered - private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint; - private float mTextHeight, mWarningTextHeight; + private boolean mInitialized; - private int mChargeColor; - private final float[] mBoltPoints; - private final Path mBoltPath = new Path(); + private Paint mTextAndBoltPaint; + private Paint mWarningTextPaint; + private Paint mClearPaint; - private final RectF mFrame = new RectF(); - private final RectF mButtonFrame = new RectF(); - private final RectF mBoltFrame = new RectF(); + private LayerDrawable mBatteryDrawable; + private Drawable mFrameDrawable; + private StopMotionVectorDrawable mLevelDrawable; + private Drawable mBoltDrawable; - public NormalBatteryMeterDrawable(Resources res, boolean horizontal) { + private BatteryMeterMode mMode; + private int mTextGravity; + + public AllInOneBatteryMeterDrawable(Resources res, BatteryMeterMode mode) { super(); - mHorizontal = horizontal; - mDisposed = false; - mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mFramePaint.setColor(mFrameColor); - mFramePaint.setDither(true); - mFramePaint.setStrokeWidth(0); - mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE); + loadBatteryDrawables(res, mode); - mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBatteryPaint.setDither(true); - mBatteryPaint.setStrokeWidth(0); - mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mMode = mode; + mDisposed = false; - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + // load text gravity and blend mode + int[] attrs = new int[] {android.R.attr.gravity, R.attr.blendMode}; + int resId = getBatteryDrawableStyleResourceForMode(mode); + PorterDuff.Mode xferMode = PorterDuff.Mode.XOR; + if (resId != 0) { + TypedArray a = getContext().obtainStyledAttributes( + getBatteryDrawableStyleResourceForMode(mode), attrs); + mTextGravity = a.getInt(0, Gravity.CENTER); + xferMode = PorterDuff.intToMode(a.getInt(1, + PorterDuff.modeToInt(PorterDuff.Mode.XOR))); + } else { + mTextGravity = Gravity.CENTER; + } + Log.d(TAG, "mTextGravity=" + mTextGravity); + + mTextAndBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); - mTextPaint.setTypeface(font); - mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextAndBoltPaint.setTypeface(font); + mTextAndBoltPaint.setTextAlign(getPaintAlignmentFromGravity(mTextGravity)); + mTextAndBoltPaint.setXfermode(new PorterDuffXfermode(xferMode)); + mTextAndBoltPaint.setColor(mCurrentFillColor != 0 + ? mCurrentFillColor + : res.getColor(R.color.batterymeter_bolt_color)); mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mWarningTextPaint.setColor(mColors[1]); font = Typeface.create("sans-serif", Typeface.BOLD); mWarningTextPaint.setTypeface(font); - mWarningTextPaint.setTextAlign(Paint.Align.CENTER); - - mChargeColor = getResources().getColor(R.color.batterymeter_charge_color); + mWarningTextPaint.setTextAlign(getPaintAlignmentFromGravity(mTextGravity)); - mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color)); - mBoltPoints = loadBoltPoints(res); + mClearPaint = new Paint(); + mClearPaint.setColor(0); } @Override public void onDraw(Canvas c, BatteryTracker tracker) { if (mDisposed) return; - final int level = tracker.level; - - if (level == BatteryTracker.UNKNOWN_LEVEL) return; - - float drawFrac = (float) level / 100f; - final int pt = getPaddingTop() + (mHorizontal ? (int)(mHeight * 0.12f) : 0); - final int pl = getPaddingLeft(); - final int pr = getPaddingRight(); - final int pb = getPaddingBottom() + (mHorizontal ? (int)(mHeight * 0.08f) : 0); - final int height = mHeight - pt - pb; - final int width = mWidth - pl - pr; - - final int buttonHeight = (int) ((mHorizontal ? width : height) * mButtonHeightFraction); - - mFrame.set(0, 0, width, height); - mFrame.offset(pl, pt); - - if (mHorizontal) { - mButtonFrame.set( - /*cover frame border of intersecting area*/ - width - buttonHeight - mFrame.left, - mFrame.top + Math.round(height * 0.25f), - mFrame.right, - mFrame.bottom - Math.round(height * 0.25f)); - - mButtonFrame.top += mSubpixelSmoothingLeft; - mButtonFrame.bottom -= mSubpixelSmoothingRight; - mButtonFrame.right -= mSubpixelSmoothingRight; - } else { - // button-frame: area above the battery body - mButtonFrame.set( - mFrame.left + Math.round(width * 0.25f), - mFrame.top, - mFrame.right - Math.round(width * 0.25f), - mFrame.top + buttonHeight); - - mButtonFrame.top += mSubpixelSmoothingLeft; - mButtonFrame.left += mSubpixelSmoothingLeft; - mButtonFrame.right -= mSubpixelSmoothingRight; - } - - // frame: battery body area - - if (mHorizontal) { - mFrame.right -= buttonHeight; - } else { - mFrame.top += buttonHeight; - } - mFrame.left += mSubpixelSmoothingLeft; - mFrame.top += mSubpixelSmoothingLeft; - mFrame.right -= mSubpixelSmoothingRight; - mFrame.bottom -= mSubpixelSmoothingRight; - - // set the battery charging color - mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level)); - - if (level >= FULL) { - drawFrac = 1f; - } else if (level <= mCriticalLevel) { - drawFrac = 0f; - } - - final float levelTop; - - if (drawFrac == 1f) { - if (mHorizontal) { - levelTop = mButtonFrame.right; - } else { - levelTop = mButtonFrame.top; - } - } else { - if (mHorizontal) { - levelTop = (mFrame.right - (mFrame.width() * (1f - drawFrac))); - } else { - levelTop = (mFrame.top + (mFrame.height() * (1f - drawFrac))); - } - } - - // define the battery shape - mShapePath.reset(); - mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top); - if (mHorizontal) { - mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top); - mShapePath.lineTo(mButtonFrame.right, mButtonFrame.bottom); - mShapePath.lineTo(mButtonFrame.left, mButtonFrame.bottom); - mShapePath.lineTo(mFrame.right, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top); - } else { - mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top); - mShapePath.lineTo(mButtonFrame.right, mFrame.top); - mShapePath.lineTo(mFrame.right, mFrame.top); - mShapePath.lineTo(mFrame.right, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top); + if (!mInitialized) { + init(); } - if (tracker.plugged) { - // define the bolt shape - final float bl = mFrame.left + mFrame.width() / (mHorizontal ? 9f : 4.5f); - final float bt = mFrame.top + mFrame.height() / (mHorizontal ? 4.5f : 6f); - final float br = mFrame.right - mFrame.width() / (mHorizontal ? 6f : 7f); - final float bb = mFrame.bottom - mFrame.height() / (mHorizontal ? 7f : 10f); - if (mBoltFrame.left != bl || mBoltFrame.top != bt - || mBoltFrame.right != br || mBoltFrame.bottom != bb) { - mBoltFrame.set(bl, bt, br, bb); - mBoltPath.reset(); - mBoltPath.moveTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); - for (int i = 2; i < mBoltPoints.length; i += 2) { - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height()); - } - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); - } - - float boltPct = mHorizontal ? - (mBoltFrame.left - levelTop) / (mBoltFrame.left - mBoltFrame.right) : - (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top); - boltPct = Math.min(Math.max(boltPct, 0), 1); - if (boltPct <= BOLT_LEVEL_THRESHOLD) { - // draw the bolt if opaque - c.drawPath(mBoltPath, mBoltPaint); - } else { - // otherwise cut the bolt out of the overall shape - mShapePath.op(mBoltPath, Path.Op.DIFFERENCE); - } - } - - // compute percentage text - boolean pctOpaque = false; - float pctX = 0, pctY = 0; - String pctText = null; - if (!tracker.plugged && level > mCriticalLevel && mShowPercent) { - mTextPaint.setColor(getColorForLevel(level)); - final float full = mHorizontal ? 0.60f : 0.45f; - final float nofull = mHorizontal ? 0.75f : 0.6f; - final float single = mHorizontal ? 0.86f : 0.75f; - mTextPaint.setTextSize(height * - (SINGLE_DIGIT_PERCENT ? single - : (tracker.level == 100 ? full : nofull))); - mTextHeight = -mTextPaint.getFontMetrics().ascent; - pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level); - pctX = mWidth * 0.5f; - pctY = (mHeight + mTextHeight) * 0.47f; - if (mHorizontal) { - pctOpaque = pctX > levelTop; - } else { - pctOpaque = levelTop > pctY; - } - if (!pctOpaque) { - mTextPath.reset(); - mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath); - // cut the percentage text out of the overall shape - mShapePath.op(mTextPath, Path.Op.DIFFERENCE); - } - } - - // draw the battery shape background - c.drawPath(mShapePath, mFramePaint); - - // draw the battery shape, clipped to charging level - if (mHorizontal) { - mFrame.right = levelTop; - } else { - mFrame.top = levelTop; - } - mClipPath.reset(); - mClipPath.addRect(mFrame, Path.Direction.CCW); - mShapePath.op(mClipPath, Path.Op.INTERSECT); - c.drawPath(mShapePath, mBatteryPaint); - - if (!tracker.plugged) { - if (level <= mCriticalLevel) { - // draw the warning text - final float x = mWidth * 0.5f; - final float y = (mHeight + mWarningTextHeight) * 0.48f; - c.drawText(mWarningString, x, y, mWarningTextPaint); - } else if (pctOpaque) { - // draw the percentage text - c.drawText(pctText, pctX, pctY, mTextPaint); - } + drawBattery(c, tracker); + if (mAnimationsEnabled) { + // TODO: Allow custom animations to be used } } @@ -740,282 +550,293 @@ public void onDispose() { @Override public void setDarkIntensity(int backgroundColor, int fillColor) { mIconTint = fillColor; - mFramePaint.setColor(backgroundColor); - mBoltPaint.setColor(fillColor); - mChargeColor = fillColor; + // Make bolt fully opaque for increased visibility + mBoltDrawable.setTint(0xff000000 | fillColor); + mFrameDrawable.setTint(backgroundColor); + updateBoltDrawableLayer(mBatteryDrawable, mBoltDrawable); invalidate(); } @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { - mHeight = h; - mWidth = w; - mWarningTextPaint.setTextSize(h * 0.75f); - mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent; - } - - private float[] loadBoltPoints(Resources res) { - final int[] pts = res.getIntArray(getBoltPointsArrayResource()); - int maxX = 0, maxY = 0; - for (int i = 0; i < pts.length; i += 2) { - maxX = Math.max(maxX, pts[i]); - maxY = Math.max(maxY, pts[i + 1]); - } - final float[] ptsF = new float[pts.length]; - for (int i = 0; i < pts.length; i += 2) { - ptsF[i] = (float)pts[i] / maxX; - ptsF[i + 1] = (float)pts[i + 1] / maxY; - } - return ptsF; + init(); } - protected int getBoltPointsArrayResource() { - return mHorizontal - ? R.array.batterymeter_inverted_bolt_points - : R.array.batterymeter_bolt_points; + private boolean isThemeApplied() { + ThemeConfig themeConfig = ThemeConfig.getBootTheme(getContext().getContentResolver()); + return themeConfig != null && + !ThemeConfig.SYSTEM_DEFAULT.equals(themeConfig.getOverlayForStatusBar()); } - } - protected class CircleBatteryMeterDrawable implements BatteryMeterDrawable { - private static final boolean SINGLE_DIGIT_PERCENT = false; - private static final boolean SHOW_100_PERCENT = false; - - private static final int FULL = 96; + private void checkBatteryMeterDrawableValid(Resources res, BatteryMeterMode mode) { + final int resId = getBatteryDrawableResourceForMode(mode); + final Drawable batteryDrawable; + try { + batteryDrawable = res.getDrawable(resId); + } catch (Resources.NotFoundException e) { + throw new BatteryMeterDrawableException(res.getResourceName(resId) + " is an " + + "invalid drawable", e); + } - public static final float STROKE_WITH = 6.5f; + // check that the drawable is a LayerDrawable + if (!(batteryDrawable instanceof LayerDrawable)) { + throw new BatteryMeterDrawableException("Expected a LayerDrawable but received a " + + batteryDrawable.getClass().getSimpleName()); + } - private boolean mDisposed; + final LayerDrawable layerDrawable = (LayerDrawable) batteryDrawable; + final Drawable frame = layerDrawable.findDrawableByLayerId(R.id.battery_frame); + final Drawable level = layerDrawable.findDrawableByLayerId(R.id.battery_fill); + final Drawable bolt = layerDrawable.findDrawableByLayerId( + R.id.battery_charge_indicator); + // now check that the required layers exist and are of the correct type + if (frame == null) { + throw new BatteryMeterDrawableException("Missing battery_frame drawble"); + } + if (bolt == null) { + throw new BatteryMeterDrawableException( + "Missing battery_charge_indicator drawable"); + } + if (level != null) { + // check that the level drawable is an AnimatedVectorDrawable + if (!(level instanceof AnimatedVectorDrawable)) { + throw new BatteryMeterDrawableException("Expected a AnimatedVectorDrawable " + + "but received a " + level.getClass().getSimpleName()); + } + // make sure we can stop motion animate the level drawable + try { + StopMotionVectorDrawable smvd = new StopMotionVectorDrawable(level); + smvd.setCurrentFraction(0.5f); + } catch (Exception e) { + throw new BatteryMeterDrawableException("Unable to perform stop motion on " + + "battery_fill drawable", e); + } + } else { + throw new BatteryMeterDrawableException("Missing battery_fill drawable"); + } + } - private int mAnimOffset; - private boolean mIsAnimating; // stores charge-animation status to reliably - //remove callbacks + private void loadBatteryDrawables(Resources res, BatteryMeterMode mode) { + if (isThemeApplied()) { + try { + checkBatteryMeterDrawableValid(res, mode); + } catch (BatteryMeterDrawableException e) { + Log.w(TAG, "Invalid themed battery meter drawable, falling back to system", e); + final Context context = getContext(); + PackageManager pm = getContext().getPackageManager(); + try { + res = pm.getThemedResourcesForApplication(context.getPackageName(), + ThemeConfig.SYSTEM_DEFAULT); + } catch (PackageManager.NameNotFoundException nnfe) { + /* ignore, this should not happen */ + } + } + } - private int mCircleSize; // draw size of circle - private RectF mRectLeft; // contains the precalculated rect used in drawArc(), - // derived from mCircleSize - private float mTextX, mTextY; // precalculated position for drawText() to appear centered + int drawableResId = getBatteryDrawableResourceForMode(mode); + mBatteryDrawable = (LayerDrawable) res.getDrawable(drawableResId); + mFrameDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_frame); + mFrameDrawable.setTint(mCurrentBackgroundColor != 0 + ? mCurrentBackgroundColor + : res.getColor(R.color.batterymeter_frame_color)); + // set the animated vector drawable we will be stop animating + Drawable levelDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_fill); + mLevelDrawable = new StopMotionVectorDrawable(levelDrawable); + mBoltDrawable = mBatteryDrawable.findDrawableByLayerId(R.id.battery_charge_indicator); + } - private Paint mTextPaint; - private Paint mFrontPaint; - private Paint mBackPaint; - private Paint mBoltPaint; - private Paint mWarningTextPaint; + private void drawBattery(Canvas canvas, BatteryTracker tracker) { + boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN; + int level = tracker.level; - private final RectF mBoltFrame = new RectF(); + if (unknownStatus || tracker.status == BatteryManager.BATTERY_STATUS_FULL) { + level = 100; + } - private int mChargeColor; - private final float[] mBoltPoints; - private final Path mBoltPath = new Path(); + mTextAndBoltPaint.setColor(getColorForLevel(level)); - public CircleBatteryMeterDrawable(Resources res) { - super(); - mDisposed = false; + // Make sure we don't draw the charge indicator if not plugged in + Drawable d = mBatteryDrawable.findDrawableByLayerId(R.id.battery_charge_indicator); + if (d instanceof BitmapDrawable) { + // In case we are using a BitmapDrawable, which we should be unless something bad + // happened, we need to change the paint rather than the alpha in case the blendMode + // has been set to clear. Clear always clears regardless of alpha level ;) + BitmapDrawable bd = (BitmapDrawable) d; + bd.getPaint().set(tracker.plugged ? mTextAndBoltPaint : mClearPaint); + } else { + d.setAlpha(tracker.plugged ? 255 : 0); + } - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); - mTextPaint.setTypeface(font); - mTextPaint.setTextAlign(Paint.Align.CENTER); - - mFrontPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mFrontPaint.setStrokeCap(Paint.Cap.BUTT); - mFrontPaint.setDither(true); - mFrontPaint.setStrokeWidth(0); - mFrontPaint.setStyle(Paint.Style.STROKE); - - mBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBackPaint.setColor(res.getColor(R.color.batterymeter_frame_color)); - mBackPaint.setStrokeCap(Paint.Cap.BUTT); - mBackPaint.setDither(true); - mBackPaint.setStrokeWidth(0); - mBackPaint.setStyle(Paint.Style.STROKE); + // Now draw the level indicator + // set the level and tint color of the fill drawable + mLevelDrawable.setCurrentFraction(level / 100f); + mLevelDrawable.setTint(getColorForLevel(level)); + mBatteryDrawable.draw(canvas); - mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mWarningTextPaint.setColor(mColors[1]); - font = Typeface.create("sans-serif", Typeface.BOLD); - mWarningTextPaint.setTypeface(font); - mWarningTextPaint.setTextAlign(Paint.Align.CENTER); + // if chosen by options, draw percentage text in the middle + // always skip percentage when 100, so layout doesnt break + if (unknownStatus) { + mTextAndBoltPaint.setColor(getContext().getColor(R.color.batterymeter_frame_color)); + canvas.drawText("?", mTextX, mTextY, mTextAndBoltPaint); - mChargeColor = getResources().getColor(R.color.batterymeter_charge_color); + } else if (!tracker.plugged) { + drawPercentageText(canvas, tracker); + } + } - mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBoltPaint.setColor(res.getColor(R.color.batterymeter_bolt_color)); - mBoltPoints = loadBoltPoints(res); + private void drawPercentageText(Canvas canvas, BatteryTracker tracker) { + final int level = tracker.level; + if (level > mCriticalLevel + && (mShowPercent && !(level == 100 && !SHOW_100_PERCENT))) { + // draw the percentage text + String pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level); + mTextAndBoltPaint.setColor(getColorForLevel(level)); + canvas.drawText(pctText, mTextX, mTextY, mTextAndBoltPaint); + } else if (level <= mCriticalLevel) { + // draw the warning text + canvas.drawText(mWarningString, mTextX, mTextY, mWarningTextPaint); + } } - @Override - public void onDraw(Canvas c, BatteryTracker tracker) { - if (mDisposed) return; + /** + * initializes all size dependent variables + */ + private void init() { + // not much we can do with zero width or height, we'll get another pass later + if (mWidth <= 0 || mHeight <=0) return; + + final float widthDiv2 = mWidth / 2f; + // text size is width / 2 - 2dp for wiggle room + final float textSize = widthDiv2 - getResources().getDisplayMetrics().density * 2; + mTextAndBoltPaint.setTextSize(textSize); + mWarningTextPaint.setTextSize(textSize); + + int pLeft = getPaddingLeft(); + Rect iconBounds = new Rect(pLeft, 0, pLeft + mWidth, mHeight); + mBatteryDrawable.setBounds(iconBounds); - if (mRectLeft == null) { - initSizeBasedStuff(); + // calculate text position + Rect bounds = new Rect(); + mTextAndBoltPaint.getTextBounds("99", 0, "99".length(), bounds); + boolean isRtl = isLayoutRtl(); + + // compute mTextX based on text gravity + if ((mTextGravity & Gravity.START) == Gravity.START) { + mTextX = isRtl ? mWidth : 0; + } else if ((mTextGravity & Gravity.END) == Gravity.END) { + mTextX = isRtl ? 0 : mWidth; + } else if ((mTextGravity & Gravity.LEFT) == Gravity.LEFT) { + mTextX = 0; + }else if ((mTextGravity & Gravity.RIGHT) == Gravity.RIGHT) { + mTextX = mWidth; + } else { + mTextX = widthDiv2 + pLeft; } - drawCircle(c, tracker, mTextX, mRectLeft); - if (mAnimationsEnabled) { - updateChargeAnim(tracker); + // compute mTextY based on text gravity + if ((mTextGravity & Gravity.TOP) == Gravity.TOP) { + mTextY = bounds.height(); + } else if ((mTextGravity & Gravity.BOTTOM) == Gravity.BOTTOM) { + mTextY = mHeight; + } else { + mTextY = widthDiv2 + bounds.height() / 2.0f; } - } - @Override - public void onDispose() { - mDisposed = true; + updateBoltDrawableLayer(mBatteryDrawable, mBoltDrawable); + + mInitialized = true; } - @Override - public void setDarkIntensity(int backgroundColor, int fillColor) { - mIconTint = fillColor; - mBoltPaint.setColor(fillColor); - mChargeColor = fillColor; - invalidate(); + private int getBatteryDrawableResourceForMode(BatteryMeterMode mode) { + switch (mode) { + case BATTERY_METER_ICON_LANDSCAPE: + return R.drawable.ic_battery_landscape; + case BATTERY_METER_CIRCLE: + return R.drawable.ic_battery_circle; + case BATTERY_METER_ICON_PORTRAIT: + return R.drawable.ic_battery_portrait; + default: + return 0; + } } - @Override - public void onSizeChanged(int w, int h, int oldw, int oldh) { - initSizeBasedStuff(); + private int getBatteryDrawableStyleResourceForMode(BatteryMeterMode mode) { + switch (mode) { + case BATTERY_METER_ICON_LANDSCAPE: + return R.style.BatteryMeterViewDrawable_Landscape; + case BATTERY_METER_CIRCLE: + return R.style.BatteryMeterViewDrawable_Circle; + case BATTERY_METER_ICON_PORTRAIT: + return R.style.BatteryMeterViewDrawable_Portrait; + default: + return R.style.BatteryMeterViewDrawable; + } } - private float[] loadBoltPoints(Resources res) { - final int[] pts = res.getIntArray(getBoltPointsArrayResource()); - int maxX = 0, maxY = 0; - for (int i = 0; i < pts.length; i += 2) { - maxX = Math.max(maxX, pts[i]); - maxY = Math.max(maxY, pts[i + 1]); + private Paint.Align getPaintAlignmentFromGravity(int gravity) { + boolean isRtl = isLayoutRtl(); + if ((gravity & Gravity.START) == Gravity.START) { + return isRtl ? Paint.Align.RIGHT : Paint.Align.LEFT; } - final float[] ptsF = new float[pts.length]; - for (int i = 0; i < pts.length; i += 2) { - ptsF[i] = (float)pts[i] / maxX; - ptsF[i + 1] = (float)pts[i + 1] / maxY; + if ((gravity & Gravity.END) == Gravity.END) { + return isRtl ? Paint.Align.LEFT : Paint.Align.RIGHT; } - return ptsF; - } + if ((gravity & Gravity.LEFT) == Gravity.LEFT) return Paint.Align.LEFT; + if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) return Paint.Align.RIGHT; - protected int getBoltPointsArrayResource() { - return R.array.batterymeter_bolt_points; + // default to center + return Paint.Align.CENTER; } - private void drawCircle(Canvas canvas, BatteryTracker tracker, - float textX, RectF drawRect) { - boolean unknownStatus = tracker.status == BatteryManager.BATTERY_STATUS_UNKNOWN; - int level = tracker.level; - Paint paint; - - if (unknownStatus) { - paint = mBackPaint; - level = 100; // Draw all the circle; + // Creates a BitmapDrawable of the bolt so we can make use of the XOR xfer mode with vector + // based drawables + private void updateBoltDrawableLayer(LayerDrawable batteryDrawable, Drawable boltDrawable) { + BitmapDrawable newBoltDrawable; + if (boltDrawable instanceof BitmapDrawable) { + newBoltDrawable = (BitmapDrawable) boltDrawable.mutate(); } else { - paint = mFrontPaint; - paint.setColor(getColorForLevel(level)); - if (tracker.status == BatteryManager.BATTERY_STATUS_FULL) { - level = 100; + Bitmap boltBitmap = createBoltBitmap(boltDrawable); + if (boltBitmap == null) { + // not much to do with a null bitmap so keep original bolt for now + return; } + Rect bounds = boltDrawable.getBounds(); + newBoltDrawable = new BitmapDrawable(getResources(), boltBitmap); + newBoltDrawable.setBounds(bounds); } - - // draw thin gray ring first - canvas.drawArc(drawRect, 270, 360, false, mBackPaint); - if (level != 0) { - // draw colored arc representing charge level - canvas.drawArc(drawRect, 270 + mAnimOffset, 3.6f * level, false, paint); - } - // if chosen by options, draw percentage text in the middle - // always skip percentage when 100, so layout doesnt break - if (unknownStatus) { - mTextPaint.setColor(paint.getColor()); - canvas.drawText("?", textX, mTextY, mTextPaint); - - } else if (tracker.plugged) { - canvas.drawPath(mBoltPath, mBoltPaint); - } else { - if (level > mCriticalLevel - && (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT))) { - // draw the percentage text - String pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level); - mTextPaint.setColor(paint.getColor()); - canvas.drawText(pctText, textX, mTextY, mTextPaint); - } else if (level <= mCriticalLevel) { - // draw the warning text - canvas.drawText(mWarningString, textX, mTextY, mWarningTextPaint); + newBoltDrawable.getPaint().set(mTextAndBoltPaint); + batteryDrawable.setDrawableByLayerId(R.id.battery_charge_indicator, newBoltDrawable); + } + + private Bitmap createBoltBitmap(Drawable boltDrawable) { + // not much we can do with zero width or height, we'll get another pass later + if (mWidth <= 0 || mHeight <= 0) return null; + + Bitmap bolt; + if (!(boltDrawable instanceof BitmapDrawable)) { + int pLeft = getPaddingLeft(); + Rect iconBounds = new Rect(pLeft, 0, pLeft + mWidth, mHeight); + bolt = Bitmap.createBitmap(iconBounds.width(), iconBounds.height(), + Bitmap.Config.ARGB_8888); + if (bolt != null) { + Canvas c = new Canvas(bolt); + c.drawColor(-1, PorterDuff.Mode.CLEAR); + boltDrawable.draw(c); } - } - } - - /** - * updates the animation counter - * cares for timed callbacks to continue animation cycles - * uses mInvalidate for delayed invalidate() callbacks - */ - private void updateChargeAnim(BatteryTracker tracker) { - // Stop animation when battery is full or after the meter - // rotated back to 0 after unplugging. - if (!tracker.shouldIndicateCharging() - || tracker.status == BatteryManager.BATTERY_STATUS_FULL - || tracker.level == 0) { - mIsAnimating = false; } else { - mIsAnimating = true; - } - - if (mAnimOffset > 360) { - mAnimOffset = 0; - } - - boolean continueAnimation = mIsAnimating || mAnimOffset != 0; - - if (continueAnimation) { - mAnimOffset += 3; + bolt = ((BitmapDrawable) boltDrawable).getBitmap(); } - if (continueAnimation) { - postInvalidateDelayed(50); - } + return bolt; } - /** - * initializes all size dependent variables - * sets stroke width and text size of all involved paints - * YES! i think the method name is appropriate - */ - private void initSizeBasedStuff() { - mCircleSize = Math.min(getMeasuredWidth(), getMeasuredHeight()); - mTextPaint.setTextSize(mCircleSize / 2f); - mWarningTextPaint.setTextSize(mCircleSize / 2f); - - float strokeWidth = mCircleSize / STROKE_WITH; - mFrontPaint.setStrokeWidth(strokeWidth); - mBackPaint.setStrokeWidth(strokeWidth); - - // calculate rectangle for drawArc calls - int pLeft = getPaddingLeft(); - mRectLeft = new RectF(pLeft + strokeWidth / 2.0f, 0 + strokeWidth / 2.0f, mCircleSize - - strokeWidth / 2.0f + pLeft, mCircleSize - strokeWidth / 2.0f); + private class BatteryMeterDrawableException extends RuntimeException { + public BatteryMeterDrawableException(String detailMessage) { + super(detailMessage); + } - // calculate Y position for text - Rect bounds = new Rect(); - mTextPaint.getTextBounds("99", 0, "99".length(), bounds); - mTextX = mCircleSize / 2.0f + getPaddingLeft(); - // the +1dp at end of formula balances out rounding issues.works out on all resolutions - mTextY = mCircleSize / 2.0f + (bounds.bottom - bounds.top) / 2.0f - - strokeWidth / 2.0f + getResources().getDisplayMetrics().density; - - // draw the bolt - final float bl = (int) (mRectLeft.left + mRectLeft.width() / 3.2f); - final float bt = (int) (mRectLeft.top + mRectLeft.height() / 4f); - final float br = (int) (mRectLeft.right - mRectLeft.width() / 5.2f); - final float bb = (int) (mRectLeft.bottom - mRectLeft.height() / 8f); - if (mBoltFrame.left != bl || mBoltFrame.top != bt - || mBoltFrame.right != br || mBoltFrame.bottom != bb) { - mBoltFrame.set(bl, bt, br, bb); - mBoltPath.reset(); - mBoltPath.moveTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); - for (int i = 2; i < mBoltPoints.length; i += 2) { - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height()); - } - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); + public BatteryMeterDrawableException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); } } } diff --git a/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java index b80e6d09beccd..a29b16ce1e7be 100755 --- a/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/DockBatteryMeterView.java @@ -18,7 +18,6 @@ import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.os.BatteryManager; import android.util.AttributeSet; import android.view.View; @@ -148,45 +147,4 @@ public void setMode(BatteryMeterMode mode) { setVisibility(View.GONE); } } - - @Override - protected BatteryMeterDrawable createBatteryMeterDrawable(BatteryMeterMode mode) { - Resources res = mContext.getResources(); - switch (mode) { - case BATTERY_METER_CIRCLE: - return new DockCircleBatteryMeterDrawable(res); - case BATTERY_METER_ICON_LANDSCAPE: - return new DockNormalBatteryMeterDrawable(res, true); - case BATTERY_METER_TEXT: - case BATTERY_METER_GONE: - return null; - default: - return new DockNormalBatteryMeterDrawable(res, false); - } - } - - protected class DockNormalBatteryMeterDrawable extends NormalBatteryMeterDrawable { - - public DockNormalBatteryMeterDrawable(Resources res, boolean horizontal) { - super(res, horizontal); - } - - @Override - protected int getBoltPointsArrayResource() { - return mHorizontal - ? R.array.dockbatterymeter_inverted_bolt_points - : R.array.dockbatterymeter_bolt_points; - } - } - - protected class DockCircleBatteryMeterDrawable extends CircleBatteryMeterDrawable { - public DockCircleBatteryMeterDrawable(Resources res) { - super(res); - } - - @Override - protected int getBoltPointsArrayResource() { - return R.array.dockbatterymeter_bolt_points; - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java index 13af3bba8624f..3cd86fefbb7f4 100644 --- a/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/cm/LockscreenShortcutsActivity.java @@ -235,13 +235,15 @@ public void onCancel(DialogInterface dialog) { private void onTargetChange(String uri) { if (uri == null) { - final GlowBackground background = (GlowBackground) mSelectedView.getBackground(); - background.hideGlow(); + if (mSelectedView != null) { + final GlowBackground background = (GlowBackground) mSelectedView.getBackground(); + background.hideGlow(); + } return; } if (uri.equals(ACTION_APP)) { - mPicker.pickShortcut(null, null, 0); + mPicker.pickShortcut(null, null, 0, false); } else { mSelectedView.setTag(uri); saveCustomActions(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index cd94c066da427..7d09c91e6da2e 100755 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -53,6 +53,7 @@ import android.util.Log; import android.util.Slog; import android.view.IWindowManager; +import android.view.View; import android.view.ViewGroup; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; @@ -61,6 +62,7 @@ import com.android.systemui.cm.UserContentObserver; import com.android.systemui.qs.tiles.LockscreenToggleTile; +import com.android.systemui.statusbar.StatusBarState; import cyanogenmod.app.Profile; import cyanogenmod.app.ProfileManager; @@ -482,21 +484,20 @@ public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simS // only force lock screen in case of missing sim if user hasn't // gone through setup wizard synchronized (this) { - if (shouldWaitForProvisioning()) { - if (!mShowing) { - if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing," - + " we need to show the keyguard since the " - + "device isn't provisioned yet."); - doKeyguardLocked(null); - } else { - resetStateLocked(); - } + if (shouldWaitForProvisioning() && !mShowing) { + if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing," + + " we need to show the keyguard since the " + + "device isn't provisioned yet."); + doKeyguardLocked(null); + } else { + resetStateLocked(); } } break; case PIN_REQUIRED: case PUK_REQUIRED: synchronized (this) { + mStatusBar.hideHeadsUp(); if (!mShowing) { if (DEBUG_SIM_STATES) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't " @@ -1294,10 +1295,31 @@ public void dismiss() { } public void showKeyguard() { + // This is to prevent left edge from interfering + // with affordances. + if (mStatusBar.isAffordanceSwipeInProgress() + || mStatusBar.getBarState() == StatusBarState.KEYGUARD) { + return; + } + + // Disable edge detector once we're back on lockscreen + try { + WindowManagerGlobal.getWindowManagerService() + .setLiveLockscreenEdgeDetector(false); + } catch (RemoteException e){ + Log.e(TAG, e.getMessage()); + } + mHandler.post(new Runnable() { @Override public void run() { + // Hide status bar window to avoid flicker, + // slideNotificationPanelIn will make it visible later. + mStatusBar.getStatusBarWindow().setVisibility(View.INVISIBLE); + // Get the keyguard into the correct state by calling mStatusBar.showKeyguard() mStatusBar.showKeyguard(); + // Now have the notification panel slid back into view + mStatusBar.slideNotificationPanelIn(); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java index 578a9832ca6b6..3e0ab8be0f965 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItemsList.java @@ -27,6 +27,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListAdapter; @@ -42,7 +43,7 @@ /** * Quick settings common detail list view with line items. */ -public class QSDetailItemsList extends LinearLayout { +public class QSDetailItemsList extends FrameLayout { private static final String TAG = "QSDetailItemsList"; private ListView mListView; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java index fdbb361d12472..4b9036e061aeb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDragPanel.java @@ -53,9 +53,11 @@ import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.cm.UserContentObserver; +import com.android.systemui.qs.tiles.CustomQSTile; import com.android.systemui.qs.tiles.EditTile; import com.android.systemui.settings.BrightnessController; import com.android.systemui.settings.ToggleSlider; +import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.QSTileHost; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.tuner.QsTuner; @@ -63,7 +65,6 @@ import cyanogenmod.app.StatusBarPanelCustomTile; import cyanogenmod.providers.CMSettings; import org.cyanogenmod.internal.logging.CMMetricsLogger; -import org.cyanogenmod.internal.util.QSConstants; import org.cyanogenmod.internal.util.QSUtils; import java.util.ArrayList; @@ -74,6 +75,8 @@ import java.util.ListIterator; import java.util.Map; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; + public class QSDragPanel extends QSPanel implements View.OnDragListener, View.OnLongClickListener { private static final String TAG = "QSDragPanel"; @@ -88,6 +91,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On protected final ArrayList mPages = new ArrayList<>(); + private NotificationPanelView mPanelView; protected QSViewPager mViewPager; protected PagerAdapter mPagerAdapter; QSPanelTopView mQsPanelTop; @@ -96,6 +100,7 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On private TextView mDetailRemoveButton; private DragTileRecord mDraggingRecord, mLastDragRecord; + private ViewGroup mDetailButtons; private boolean mEditing; private boolean mDragging; private float mLastTouchLocationX, mLastTouchLocationY; @@ -113,9 +118,6 @@ public class QSDragPanel extends QSPanel implements View.OnDragListener, View.On List mCurrentlyAnimating = Collections.synchronizedList(new ArrayList()); - private Point mDisplaySize; - private int[] mTmpLoc; - private Runnable mResetPage = new Runnable() { @Override public void run() { @@ -139,6 +141,7 @@ protected void setupViews() { updateResources(); mDetail = LayoutInflater.from(mContext).inflate(R.layout.qs_detail, this, false); + mDetailButtons = (ViewGroup) mDetail.findViewById(R.id.buttons); mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content); mDetailRemoveButton = (TextView) mDetail.findViewById(android.R.id.button3); mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2); @@ -364,7 +367,14 @@ public void setBrightnessMirror(BrightnessMirrorController c) { protected void drawTile(TileRecord r, QSTile.State state) { if (mEditing) { - state.visible = true; + if ((r.tile instanceof CustomQSTile) + && (((CustomQSTile) r.tile).isUserRemoved() + || ((CustomQSTile) r.tile).getTile() == null)) { + // don't modify visibility state if removed, or not yet published + } else { + state.visible = true; + state.enabled = true; + } } final int visibility = state.visible ? VISIBLE : GONE; setTileVisibility(r.tileView, visibility); @@ -611,6 +621,13 @@ public void setTiles(final Collection> tilesCollection) { final Iterator> newTileIterator = tilesCollection.iterator(); while (newTileIterator.hasNext()) { QSTile tile = newTileIterator.next(); + if (tile instanceof CustomQSTile) { + if (((CustomQSTile) tile).isUserRemoved() + || ((CustomQSTile) tile).getTile() == null) { + // tile not published yet + continue; + } + } final int tileDestPage = getPagesForCount(runningCount + 1) - 1; if (DEBUG_TILES) { @@ -770,13 +787,6 @@ public int getTilesPerPage(boolean firstPage) { return QSTileHost.TILES_PER_PAGE; } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mTmpLoc = null; - mDisplaySize = null; - } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); @@ -791,37 +801,18 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mFooter.hasFooter()) { h += mFooter.getView().getMeasuredHeight(); } + mGridHeight = h; + mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED); + if (mDetail.getMeasuredHeight() < h) { mDetail.measure(exactly(width), exactly(h)); } - - // Check if the detail view would be overflowing below the physical height of the device - // and cutting the content off. If it is, reduce the detail height to fit. - if (isShowingDetail()) { - if (mDisplaySize == null) { - mDisplaySize = new Point(); - getDisplay().getSize(mDisplaySize); - } - if (mTmpLoc == null) { - mTmpLoc = new int[2]; - mDetail.getLocationOnScreen(mTmpLoc); - } - - final int containerTop = mTmpLoc[1]; - final int detailBottom = containerTop + mDetail.getMeasuredHeight(); - if (detailBottom >= mDisplaySize.y) { - // panel is hanging below the screen - final int detailMinHeight = mDisplaySize.y - containerTop; - mDetail.measure(exactly(width), exactly(detailMinHeight)); - } - setMeasuredDimension(width, mDetail.getMeasuredHeight()); - mGridHeight = mDetail.getMeasuredHeight(); - } else { - setMeasuredDimension(width, h); - mGridHeight = h; + if (isShowingDetail() && !isClosingDetail() && mExpanded) { + h = mDetail.getMeasuredHeight(); } + setMeasuredDimension(width, h); for (TileRecord record : mRecords) { setupRecord(record); } @@ -851,11 +842,13 @@ protected void handleShowDetailTile(TileRecord r, boolean show) { } r.tile.setDetailListening(show); int x = (int) ((DragTileRecord) r).destination.x + r.tileView.getWidth() / 2; - int y = mViewPager.getTop() + (int) ((DragTileRecord) r).destination.y + r.tileView.getHeight() / 2; + int y = mViewPager.getTop() + + (int) ((DragTileRecord) r).destination.y + r.tileView.getHeight() / 2; handleShowDetailImpl(r, show, x, y); } else { super.handleShowDetailTile(r, show); } + mPageIndicator.setVisibility(!show ? View.VISIBLE : View.INVISIBLE); } @Override @@ -868,9 +861,6 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { // view pager laid out from top of brightness view to bottom to page through settings mViewPager.layout(0, 0, w, viewPagerBottom); - // layout page indicator inside viewpager inset - mPageIndicator.layout(0, b - mPageIndicatorHeight, w, b); - mDetail.layout(0, 0, w, mDetail.getMeasuredHeight()); if (mFooter.hasFooter()) { @@ -881,7 +871,10 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { if (!isShowingDetail() && !isClosingDetail()) { mQsPanelTop.bringToFront(); + } + // layout page indicator inside viewpager inset + mPageIndicator.layout(0, b - mPageIndicatorHeight, w, b); } protected int getRowTop(int row) { @@ -1082,6 +1075,17 @@ public void run() { } }); break; + } else if (mDraggingRecord.tile instanceof CustomQSTile) { + ((CustomQSTile) mDraggingRecord.tile).setUserRemoved(true); + final String spec = mHost.getSpec(mDraggingRecord.tile); + restoreDraggingTilePosition(v, new Runnable() { + @Override + public void run() { + // it might get added back later by the app, but that's ok, + // we just want to reset its position after it has been removed. + mHost.remove(spec); + } + }); } else { mRestored = true; removeDraggingRecord(); @@ -1805,12 +1809,16 @@ public void onClick(View v) { } }); } + mPanelView.setDetailRequestedScrollLock(mExpanded && show + && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE); } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); FontSizeUtils.updateFontSize(mDetailRemoveButton, R.dimen.qs_detail_button_text_size); + mPanelView.setDetailRequestedScrollLock(mExpanded && isShowingDetail() + && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE); } @Override @@ -1842,10 +1850,11 @@ public void updateResources() { for (TileRecord r : mRecords) { r.tile.clearState(); } + updateDetailText(); + mQsPanelTop.updateResources(); if (mListening) { refreshAllTiles(); } - updateDetailText(); } } @@ -1859,6 +1868,10 @@ public void cleanup() { } } + public void setPanelView(NotificationPanelView panelView) { + this.mPanelView = panelView; + } + public static class TilesListAdapter extends BaseExpandableListAdapter implements QSTile.DetailAdapter { @@ -1885,7 +1898,8 @@ public TilesListAdapter(Context context, QSDragPanel panel) { final Iterator i = tiles.iterator(); while (i.hasNext()) { final String spec = i.next(); - if (QSUtils.isStaticQsTile(spec) || QSUtils.isDynamicQsTile(spec)) { + if (QSUtils.isStaticQsTile(spec) + || QSUtils.isDynamicQsTile(extractTileTagFromSpec(spec))) { List packageList = mPackageTileMap.get(PACKAGE_ANDROID); packageList.add(spec); } else { @@ -1898,13 +1912,121 @@ public TilesListAdapter(Context context, QSDragPanel panel) { } } + final Map stringMap = CustomQSTile.getCustomQSTilePrefs(mContext).getAll(); + for (Map.Entry entry : stringMap.entrySet()) { + if (entry.getValue() instanceof Boolean) { + if ((Boolean)entry.getValue()) { + final String key = entry.getKey(); + if (QSUtils.isDynamicQsTile(extractTileTagFromSpec(key))) { + mPackageTileMap.get(PACKAGE_ANDROID).add(key); + } else { + final String customTilePackage = getCustomTilePackage(key); + List packageList = mPackageTileMap.get(customTilePackage); + if (packageList == null) { + mPackageTileMap.put(customTilePackage, + packageList = new ArrayList<>()); + } + packageList.add(key); + + } + } + } + }; + final List systemTiles = mPackageTileMap.get(PACKAGE_ANDROID); Collections.sort(systemTiles); } private String getCustomTilePackage(String spec) { - StatusBarPanelCustomTile sbc = mHost.getCustomTileData().get(spec).sbc; - return sbc.getPackage(); + if (mHost.getCustomTileData().get(spec) != null) { + StatusBarPanelCustomTile sbc = mHost.getCustomTileData().get(spec).sbc; + return sbc.getPackage(); + } else { + return extractPackageFromCustomTileSpec(spec); + } + } + + private static String extractPackageFromCustomTileSpec(String spec) { + if (spec != null && !spec.isEmpty()) { + final String[] split = spec.split("\\|"); + if (split != null && split.length > 2) { + return split[1]; + } + } + return null; + } + + private static String extractTileTagFromSpec(String spec) { + if (spec != null && !spec.isEmpty()) { + final String[] split = spec.split("\\|"); + if (split != null && split.length == 5) { + /** for {@link cyanogenmod.app.StatusBarPanelCustomTile#key() **/ + return split[3]; + } else if (split != null && split.length == 3) { + /** for {@link cyanogenmod.app.StatusBarPanelCustomTile#persistableKey()} **/ + return split[2]; + } + } + return null; + } + + private Drawable getQSTileIcon(String spec) { + if (QSUtils.isDynamicQsTile(spec)) { + return QSTile.ResourceIcon.get( + QSUtils.getDynamicQSTileResIconId(mContext, UserHandle.myUserId(), spec)) + .getDrawable(mContext); + } else if (QSUtils.isStaticQsTile(spec)) { + final int res = QSTileHost.getIconResource(spec); + if (res != 0) { + return QSTile.ResourceIcon.get(res).getDrawable(mContext); + } else { + return mContext.getPackageManager().getDefaultActivityIcon(); + } + } else { + QSTile tile = mHost.getTile(spec); + if (tile != null) { + QSTile.State state = tile.getState(); + if (state != null && state.icon != null) { + return state.icon.getDrawable(mContext); + } + } + return getPackageDrawable(getCustomTilePackage(spec)); + } + } + + private String getPackageLabel(String packageName) { + try { + return mContext.getPackageManager().getApplicationLabel( + mContext.getPackageManager().getApplicationInfo(packageName, 0)).toString(); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + private Drawable getPackageDrawable(String packageName) { + try { + return mContext.getPackageManager().getApplicationIcon(packageName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + private String getQSTileLabel(String spec) { + if (QSUtils.isStaticQsTile(spec)) { + int resource = QSTileHost.getLabelResource(spec); + if (resource != 0) { + return mContext.getText(resource).toString(); + } else { + return spec; + } + } else if (QSUtils.isDynamicQsTile(extractTileTagFromSpec(spec))) { + return QSUtils.getDynamicQSTileLabel(mContext, + UserHandle.myUserId(), extractTileTagFromSpec(spec)); + } else { + return getPackageLabel(getCustomTilePackage(spec)); + } } @Override @@ -1967,6 +2089,7 @@ public View getGroupView(int groupPosition, boolean isExpanded, View convertView // special icon systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_system); } else { + group = getPackageLabel(group); systemOrAppIcon.setImageResource(R.drawable.ic_qs_tile_category_other); } title.setText(group); @@ -2005,65 +2128,6 @@ public View getChildView(int groupPosition, int childPosition, boolean isLastChi return child; } - private String getQSTileLabel(String spec) { - if (QSUtils.isStaticQsTile(spec)) { - int resource = QSTileHost.getLabelResource(spec); - if (resource != 0) { - return mContext.getText(resource).toString(); - } else { - return spec; - } - } else if (QSUtils.isDynamicQsTile(spec)) { - return QSUtils.getDynamicQSTileLabel(mContext, - UserHandle.myUserId(), spec); - } else { - return getPackageLabel(getCustomTilePackage(spec)); - } - } - - private Drawable getQSTileIcon(String spec) { - if (QSUtils.isDynamicQsTile(spec)) { - return QSTile.ResourceIcon.get( - QSUtils.getDynamicQSTileResIconId(mContext, UserHandle.myUserId(), spec)) - .getDrawable(mContext); - } else if (QSUtils.isStaticQsTile(spec)) { - final int res = QSTileHost.getIconResource(spec); - if (res != 0) { - return QSTile.ResourceIcon.get(res).getDrawable(mContext); - } else { - return mContext.getPackageManager().getDefaultActivityIcon(); - } - } else { - QSTile tile = mHost.getTile(spec); - if (tile != null) { - QSTile.State state = tile.getState(); - if (state != null && state.icon != null) { - return state.icon.getDrawable(mContext); - } - } - return getPackageDrawable(getCustomTilePackage(spec)); - } - } - - private String getPackageLabel(String packageName) { - try { - return mContext.getPackageManager().getApplicationLabel( - mContext.getPackageManager().getApplicationInfo(packageName, 0)).toString(); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - private Drawable getPackageDrawable(String packageName) { - try { - return mContext.getPackageManager().getApplicationIcon(packageName); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return null; - } - @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; @@ -2104,7 +2168,21 @@ public boolean onTouch(View v, MotionEvent event) { public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { String spec = getChild(groupPosition, childPosition); - mPanel.add(spec); + + final QSTile tile = mHost.getTile(spec); + if (tile != null && tile instanceof CustomQSTile) { + // already present + ((CustomQSTile) tile).setUserRemoved(false); + mPanel.refreshAllTiles(); + } else { + // reset its state just in case it's not published + CustomQSTile.getCustomQSTilePrefs(mContext) + .edit() + .remove(spec) + .apply(); + mPanel.add(spec); + // TODO notify user the app isn't publishing the tile, but it now can be! + } mPanel.closeDetail(); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 60dc787fd028c..77ede938f3aa3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -72,7 +72,7 @@ public class QSPanel extends ViewGroup { protected int mDualTileUnderlap; protected int mBrightnessPaddingTop; protected int mGridHeight; - private boolean mExpanded; + protected boolean mExpanded; protected boolean mListening; private boolean mClosingDetail; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java index 5f57be173e979..b00483ca607b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelTopView.java @@ -53,6 +53,7 @@ public class QSPanelTopView extends FrameLayout { protected View mBrightnessView; protected TextView mToastView; protected View mAddTarget; + protected TextView mEditInstructionText; private boolean mEditing = false; private boolean mDisplayingInstructions = false; @@ -112,6 +113,14 @@ protected void onFinishInflate() { mBrightnessView = findViewById(R.id.brightness_container); mToastView = (TextView) findViewById(R.id.qs_toast); mAddTarget = findViewById(R.id.add_target); + mEditInstructionText = (TextView) findViewById(R.id.edit_text_instruction); + updateResources(); + } + + public void updateResources() { + if (mEditInstructionText != null) { + mEditInstructionText.setText(R.string.qs_tile_edit_header_instruction); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index a798e4e4cfe63..cdedc26695fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -225,6 +225,7 @@ public View createDetailView(Context context, View convertView, ViewGroup parent listView.setOnItemClickListener(this); listView.setAdapter(mAdapter = new QSDetailItemsList.QSDetailListAdapter(context, mBluetoothItems)); + mAdapter.setCallback(this); mItemsList.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty, R.string.quick_settings_bluetooth_detail_empty_text); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java index d09ca92121b24..40c7184ba43f5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomQSTile.java @@ -19,6 +19,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.ThemeConfig; import android.net.Uri; @@ -31,15 +32,12 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RemoteViews; import android.widget.TextView; -import com.android.internal.logging.MetricsLogger; - import com.android.systemui.qs.QSDetailItemsGrid; import com.android.systemui.qs.QSDetailItemsList; import cyanogenmod.app.CustomTile; @@ -53,6 +51,8 @@ public class CustomQSTile extends QSTile { + private static final String HIDDEN_TILES_PREF_NAME = "user_hidden_qs_tiles"; + private CustomTile.ExpandedStyle mExpandedStyle; private PendingIntent mOnClick; private PendingIntent mOnLongClick; @@ -61,10 +61,51 @@ public class CustomQSTile extends QSTile { private StatusBarPanelCustomTile mTile; private CustomQSDetailAdapter mDetailAdapter; private boolean mCollapsePanel; + private boolean mUserRemoved; + private String mPersistedPlaceHolderKey; + + public CustomQSTile(Host host, String persistedSpec) { + super(host); + mTile = null; + mPersistedPlaceHolderKey = persistedSpec; + } public CustomQSTile(Host host, StatusBarPanelCustomTile tile) { super(host); mTile = tile; + mUserRemoved = getIsUserRemovedPersisted(); + } + + private String getPersistableKey() { + if (mPersistedPlaceHolderKey != null) { + return mPersistedPlaceHolderKey; + } else { + return getTile().persistableKey(); + } + } + + private boolean getIsUserRemovedPersisted() { + return getCustomQSTilePrefs(mContext).getBoolean(getPersistableKey(), false); + } + + public boolean isUserRemoved() { + return mUserRemoved; + } + + public void setUserRemoved(boolean removed) { + if (mUserRemoved != removed) { + if (removed) { + getCustomQSTilePrefs(mContext).edit().putBoolean(getPersistableKey(), true).apply(); + } else { + getCustomQSTilePrefs(mContext).edit().remove(getPersistableKey()).apply(); + } + mUserRemoved = removed; + refreshState(); + } + } + + public static SharedPreferences getCustomQSTilePrefs(Context context) { + return context.getSharedPreferences(HIDDEN_TILES_PREF_NAME, Context.MODE_PRIVATE); } @Override @@ -138,11 +179,18 @@ public StatusBarPanelCustomTile getTile() { protected void handleUpdateState(State state, Object arg) { if (arg instanceof StatusBarPanelCustomTile) { mTile = (StatusBarPanelCustomTile) arg; + mPersistedPlaceHolderKey = null; + mUserRemoved = getIsUserRemovedPersisted(); + } + if (mTile == null) { + state.visible = false; + // nothing to show, it's a place holder for now + return; } final CustomTile customTile = mTile.getCustomTile(); state.contentDescription = customTile.contentDescription; state.label = customTile.label; - state.visible = true; + state.visible = !mUserRemoved; final int iconId = customTile.icon; if (iconId != 0 && (customTile.remoteIcon == null)) { final String iconPackage = mTile.getResPkg(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 1bfbb8fe47c88..a5ffd23824acf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -22,12 +22,14 @@ import android.content.IntentFilter; import android.nfc.NfcAdapter; +import android.util.Log; import com.android.systemui.R; import com.android.systemui.qs.QSTile; import org.cyanogenmod.internal.logging.CMMetricsLogger; +import org.cyanogenmod.internal.util.QSUtils; public class NfcTile extends QSTile { - private NfcAdapter mNfcAdapter; + private boolean mListening; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -36,10 +38,11 @@ public void onReceive(Context context, Intent intent) { refreshState(); } }; + private final boolean mSupportsNfc; public NfcTile(Host host) { super(host); - mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); + mSupportsNfc = QSUtils.deviceSupportsNfc(mContext); } @Override @@ -49,7 +52,9 @@ protected BooleanState newTileState() { @Override protected void handleClick() { - toggleState(); + boolean newState = !getState().value; + setState(newState); + refreshState(); } @Override @@ -57,23 +62,45 @@ protected void handleLongClick() { mHost.startActivityDismissingKeyguard(new Intent("android.settings.NFC_SETTINGS")); } - protected void toggleState() { - int state = getNfcState(); - switch (state) { - case NfcAdapter.STATE_TURNING_ON: - case NfcAdapter.STATE_ON: - mNfcAdapter.disable(); - break; - case NfcAdapter.STATE_TURNING_OFF: - case NfcAdapter.STATE_OFF: - mNfcAdapter.enable(); - break; + private void setState(boolean on) { + try { + NfcAdapter nfcAdapter = NfcAdapter.getNfcAdapter(mContext); + if (nfcAdapter == null) { + Log.e(TAG, "tried to set NFC state, but no NFC adapter was found"); + return; + } + if (on) { + nfcAdapter.enable(); + } else { + nfcAdapter.disable(); + } + } catch (UnsupportedOperationException e) { + // ignore + } + } + + private int getNfcAdapterState() { + try { + NfcAdapter nfcAdapter = NfcAdapter.getNfcAdapter(mContext); + if (nfcAdapter == null) { + Log.e(TAG, "tried to get NFC state, but no NFC adapter was found"); + return NfcAdapter.STATE_OFF; + } + return nfcAdapter.getAdapterState(); + } catch (UnsupportedOperationException e) { + // ignore + return NfcAdapter.STATE_OFF; } } - private boolean isEnabled() { - int state = getNfcState(); - switch (state) { + /** + * Helper method to encapsulate intermediate states (turning off/on) to help determine whether + * the adapter will be on or off. + * @param nfcState The current NFC adapter state. + * @return boolean representing what state the adapter is/will be in + */ + private static boolean isEnabled(int nfcState) { + switch (nfcState) { case NfcAdapter.STATE_TURNING_ON: case NfcAdapter.STATE_ON: return true; @@ -84,17 +111,28 @@ private boolean isEnabled() { } } - private int getNfcState() { - return mNfcAdapter.getAdapterState(); + /** + * Helper method to determine intermediate states + * @param nfcState The current NFC adapter state. + * @return boolean representing if the adapter is in an intermediate state + */ + private static boolean isEnablingDisabling(int nfcState) { + switch (nfcState) { + case NfcAdapter.STATE_TURNING_OFF: + case NfcAdapter.STATE_TURNING_ON: + return true; + default: + return false; + } } @Override protected void handleUpdateState(BooleanState state, Object arg) { - if (mNfcAdapter == null) { - mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); - } - state.visible = mNfcAdapter != null; - state.value = mNfcAdapter != null && isEnabled(); + state.visible = mSupportsNfc; + final int nfcState = getNfcAdapterState(); + state.value = mSupportsNfc && isEnabled(nfcState); + state.enabled = mSupportsNfc && !isEnablingDisabling(nfcState); + state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_nfc_on : R.drawable.ic_qs_nfc_off); state.label = mContext.getString(R.string.quick_settings_nfc_label); @@ -110,12 +148,9 @@ public void setListening(boolean listening) { if (mListening == listening) return; mListening = listening; if (listening) { - if (mNfcAdapter == null) { - mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); - refreshState(); - } mContext.registerReceiver(mReceiver, new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)); + refreshState(); } else { mContext.unregisterReceiver(mReceiver); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java index e6e6bb402e6fc..486368345245e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/PerfProfileTile.java @@ -48,6 +48,7 @@ public class PerfProfileTile extends QSTile { private final String[] mDescriptionEntries; private final String[] mAnnouncementEntries; private final int[] mPerfProfileValues; + private final int mNumPerfProfiles; private final Icon mIcon; private final PowerManager mPm; @@ -61,16 +62,36 @@ public PerfProfileTile(Host host) { mObserver = new PerformanceProfileObserver(mHandler); mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mPerformanceManager = PerformanceManager.getInstance(mContext); + mNumPerfProfiles = mPerformanceManager.getNumberOfProfiles(); - Resources res = mContext.getResources(); - - mPerfProfileValues = res.getIntArray(org.cyanogenmod.platform.internal.R.array.perf_profile_values); - - mEntries = res.getStringArray(org.cyanogenmod.platform.internal.R.array.perf_profile_entries); - mDescriptionEntries = res.getStringArray(R.array.perf_profile_description); - mAnnouncementEntries = res.getStringArray(R.array.perf_profile_announcement); + mPerfProfileValues = new int[mNumPerfProfiles]; + mEntries = new String[mNumPerfProfiles]; + mDescriptionEntries = new String[mNumPerfProfiles]; + mAnnouncementEntries = new String[mNumPerfProfiles]; mIcon = ResourceIcon.get(R.drawable.ic_qs_perf_profile); + + // Filter out unsupported profiles + Resources res = mContext.getResources(); + final int[] perfProfileValues = res.getIntArray( + org.cyanogenmod.platform.internal.R.array.perf_profile_values); + final String[] entries = res.getStringArray( + org.cyanogenmod.platform.internal.R.array.perf_profile_entries); + final String[] descriptionEntries = res.getStringArray( + R.array.perf_profile_description); + final String[] announcementEntries = res.getStringArray( + R.array.perf_profile_announcement); + int i = 0; + + for (int j = 0; j < perfProfileValues.length; j++) { + if (perfProfileValues[j] < mNumPerfProfiles) { + mPerfProfileValues[i] = perfProfileValues[j]; + mEntries[i] = entries[j]; + mDescriptionEntries[i] = descriptionEntries[j]; + mAnnouncementEntries[i] = announcementEntries[j]; + i++; + } + } } @Override @@ -135,7 +156,7 @@ public void onChange(boolean selfChange) { public void startObserving() { mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(CMSettings.Secure.PERFORMANCE_PROFILE), + CMSettings.Secure.getUriFor(CMSettings.Secure.PERFORMANCE_PROFILE), false, this); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index f4fe677492cd4..9e08599ab5e13 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -85,6 +85,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Runnable to be executed after we paused ourselves Runnable mAfterPauseRunnable; + private ReferenceCountedTrigger mExitTrigger; + /** * A common Runnable to finish Recents either by calling finish() (with a custom animation) or * launching Home with some ActivityOptions. Generally we always launch home when we exit @@ -95,6 +97,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView class FinishRecentsRunnable implements Runnable { Intent mLaunchIntent; ActivityOptions mLaunchOpts; + boolean mAbort = false; /** * Creates a finish runnable that starts the specified intent, using the given @@ -105,8 +108,15 @@ public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) { mLaunchOpts = opts; } + public void setAbort(boolean run) { + this.mAbort = run; + } + @Override public void run() { + if (mAbort) { + return; + } // Finish Recents if (mLaunchIntent != null) { try { @@ -317,13 +327,26 @@ boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) { return false; } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (!hasFocus && mExitTrigger != null && mExitTrigger.getCount() > 0) { + // we are animating recents out and the window has lost focus during the + // animation. we need to stop everything we're doing now and get out + // without any animations (since we were already animating) + mFinishLaunchHomeRunnable.setAbort(true); + finish(); + overridePendingTransition(0, 0); + } + } + /** Dismisses Recents directly to Home. */ void dismissRecentsToHomeRaw(boolean animated) { if (animated) { - ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this, + mExitTrigger = new ReferenceCountedTrigger(this, null, mFinishLaunchHomeRunnable, null); mRecentsView.startExitToHomeAnimation( - new ViewAnimation.TaskViewExitContext(exitTrigger)); + new ViewAnimation.TaskViewExitContext(mExitTrigger)); } else { mFinishLaunchHomeRunnable.run(); } @@ -458,6 +481,9 @@ protected void onPause() { @Override protected void onStop() { super.onStop(); + + mExitTrigger = null; + MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY); RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SystemServicesProxy ssp = loader.getSystemServicesProxy(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index dc0f5f92a7858..e958ee180b136 100755 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -226,6 +226,8 @@ public abstract class BaseStatusBar extends SystemUI implements protected WindowManager mWindowManager; protected IWindowManager mWindowManagerService; + private NotificationManager mNoMan; + protected abstract void refreshLayout(int layoutDirection); protected Display mDisplay; @@ -432,9 +434,7 @@ public void onReceive(Context context, Intent intent) { } } } else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) { - NotificationManager noMan = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - noMan.cancel(R.id.notification_hidden); + mNoMan.cancel(R.id.notification_hidden); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); @@ -563,6 +563,9 @@ private void updateCurrentProfilesCache() { public void start() { mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); + + mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + mDisplay = mWindowManager.getDefaultDisplay(); mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService( Context.DEVICE_POLICY_SERVICE); @@ -728,9 +731,7 @@ protected void notifyUserAboutHiddenNotifications() { mContext.getString(R.string.hidden_notifications_setup), setupIntent); - NotificationManager noMan = - (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - noMan.notify(R.id.notification_hidden, note.build()); + mNoMan.notify(R.id.notification_hidden, note.build()); } } @@ -956,7 +957,9 @@ public void onClick(View v) { } }); - filterButton.setVisibility(View.VISIBLE); + Notification notification = sbn.getNotification(); + filterButton.setVisibility(SpamFilter.hasFilterableContent(notification) + ? View.VISIBLE : View.GONE); filterButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { AsyncTask.execute(new Runnable() { @@ -1293,6 +1296,20 @@ protected void workAroundBadLayerDrawableOpacity(View v) { } protected boolean inflateViews(Entry entry, ViewGroup parent) { + final StatusBarNotification sbn = entry.notification; + String themePackageName = mCurrentTheme != null + ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName()) : null; + boolean inflated = inflateViews(entry, parent, true); + if (!inflated && themePackageName != null + && !ThemeConfig.SYSTEM_DEFAULT.equals(themePackageName)) { + Log.w(TAG, "Couldn't expand themed RemoteViews, trying unthemed for: " + sbn); + inflated = inflateViews(entry, mStackScroller, false); + } + + return inflated; + } + + protected boolean inflateViews(Entry entry, ViewGroup parent, boolean isThemeable) { PackageManager pmUser = getPackageManagerForUser( entry.notification.getUser().getIdentifier()); @@ -1369,10 +1386,12 @@ protected boolean inflateViews(Entry entry, ViewGroup parent) { View contentViewLocal = null; View bigContentViewLocal = null; View headsUpContentViewLocal = null; - String themePackageName = mCurrentTheme != null - ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName()) : null; - String statusBarThemePackageName = mCurrentTheme != null - ? mCurrentTheme.getOverlayForStatusBar() : null; + String themePackageName = (isThemeable && mCurrentTheme != null) + ? mCurrentTheme.getOverlayPkgNameForApp(sbn.getPackageName()) + : ThemeConfig.SYSTEM_DEFAULT; + String statusBarThemePackageName = (isThemeable && mCurrentTheme != null) + ? mCurrentTheme.getOverlayForStatusBar() + : ThemeConfig.SYSTEM_DEFAULT; try { contentViewLocal = contentView.apply( @@ -1463,8 +1482,10 @@ protected boolean inflateViews(Entry entry, ViewGroup parent) { } if (publicViewLocal == null) { + final Context layoutContext = isThemeable ? mContext + : maybeGetThemedContext(mContext, ThemeConfig.SYSTEM_DEFAULT); // Add a basic notification template - publicViewLocal = LayoutInflater.from(mContext).inflate( + publicViewLocal = LayoutInflater.from(layoutContext).inflate( R.layout.notification_public_default, contentContainerPublic, false); publicViewLocal.setIsRootNamespace(true); @@ -1899,7 +1920,18 @@ protected void updateRowStates() { } private boolean shouldShowOnKeyguard(StatusBarNotification sbn) { - return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey()); + if (!mShowLockscreenNotifications || mNotificationData.isAmbient(sbn.getKey())) { + return false; + } + final int showOnKeyguard = mNoMan.getShowNotificationForPackageOnKeyguard( + sbn.getPackageName(), sbn.getUid()); + boolean isKeyguardAllowedForApp = + (showOnKeyguard & Notification.SHOW_ALL_NOTI_ON_KEYGUARD) != 0; + if (isKeyguardAllowedForApp && sbn.isOngoing()) { + isKeyguardAllowedForApp = + (showOnKeyguard & Notification.SHOW_NO_ONGOING_NOTI_ON_KEYGUARD) == 0; + } + return isKeyguardAllowedForApp; } protected void setZenMode(int mode) { @@ -2310,4 +2342,24 @@ public void startAssist(Bundle args) { mAssistManager.startAssist(args); } } + + /** + * Returns a context with the given theme applied or the original context if we fail to get a + * themed context. + */ + private Context maybeGetThemedContext(Context context, String themePkg) { + Context themedContext; + try { + ApplicationInfo ai = context.getPackageManager().getApplicationInfo( + context.getPackageName(), 0); + themedContext = context.createApplicationContext(ai, themePkg, + 0); + } catch (PackageManager.NameNotFoundException e) { + themedContext = null; + } + if (themedContext == null) { + themedContext = context; + } + return themedContext; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java index 4be72921c66cd..42974baf1b183 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CustomTileData.java @@ -29,7 +29,7 @@ public static final class Entry { public final StatusBarPanelCustomTile sbc; public Entry(StatusBarPanelCustomTile sbc) { - this.key = sbc.getKey(); + this.key = sbc.persistableKey(); this.sbc = sbc; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java b/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java index f88baedba0267..1da2e5e50180f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java @@ -62,7 +62,7 @@ public class QueueView extends LinearLayout implements public void onPlaybackStateChanged(@NonNull PlaybackState state) { super.onPlaybackStateChanged(state); - if (updateQueue(mController.getQueue())) { + if (getParent() != null && updateQueue(mController.getQueue())) { getParent().requestLayout(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java index 02ab3cacfa247..538140c7179d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/VisualizerView.java @@ -195,14 +195,6 @@ protected void onDetachedFromWindow() { mCurrentBitmap = null; } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - final int size = Math.min(getMeasuredWidth(), getMeasuredHeight()); - setMeasuredDimension(size, size); - } - @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index e71d165eb2e8e..e1a345fb7f943 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -242,6 +242,13 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } + public boolean isOnLockIcon(MotionEvent event) { + final float x = event.getX(); + final float y = event.getRawY(); + + return isOnIcon(mCenterIcon, x, y); + } + public void startHintAnimation(boolean right, Runnable onFinishedListener) { cancelAnimation(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 4d56d4f28a95f..b244e26cb6617 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -72,6 +72,8 @@ import com.android.systemui.statusbar.policy.FlashlightController; import com.android.systemui.statusbar.policy.PreviewInflater; +import java.util.Objects; + import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; @@ -88,6 +90,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance"; public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture"; public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap"; + public static final String CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE = "screen_gesture"; public static final String EXTRA_CAMERA_LAUNCH_SOURCE = "com.android.systemui.camera_launch_source"; @@ -130,6 +133,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private final WindowManager.LayoutParams mWindowLayoutParams; private OnInterceptTouchEventListener mInterceptTouchListener; private BroadcastReceiver mDevicePolicyReceiver; + private Intent mLastCameraIntent; private final ServiceConnection mPrewarmConnection = new ServiceConnection() { @@ -146,14 +150,12 @@ public void onServiceDisconnected(ComponentName name) { @Override public void setVisibility(int visibility) { - if (visibility != getVisibility()) { - if (visibility == View.VISIBLE) { - if (!mBottomAreaAttached) { - addKeyguardBottomArea(false); - } - } else if (mBottomAreaAttached) { - removeKeyguardBottomArea(); + if (visibility == View.VISIBLE) { + if (!mBottomAreaAttached) { + addKeyguardBottomArea(false); } + } else if (mBottomAreaAttached) { + removeKeyguardBottomArea(); } super.setVisibility(visibility); } @@ -568,8 +570,9 @@ public void unbindCameraPrewarmService(boolean launched) { public void launchCamera(String source) { final Intent intent; - if (source.equals(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) || !mShortcutHelper - .isTargetCustom(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT)) { + if (source.equals(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) || + source.equals(CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE) || + !mShortcutHelper.isTargetCustom(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT)) { intent = getCameraIntent(); } else { intent = mShortcutHelper.getIntent(LockscreenShortcutsHelper.Shortcuts.RIGHT_SHORTCUT); @@ -721,9 +724,18 @@ private void inflateCameraPreview() { if (isTargetCustom(Shortcuts.RIGHT_SHORTCUT)) { mPreviewContainer.removeView(mCameraPreview); } else { - mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); + Intent cameraIntent = getCameraIntent(); + if (!Objects.equals(cameraIntent, mLastCameraIntent)) { + if (mCameraPreview != null) { + mPreviewContainer.removeView(mCameraPreview); + } + mCameraPreview = mPreviewInflater.inflatePreview(cameraIntent); + if (mCameraPreview != null) { + mPreviewContainer.addView(mCameraPreview); + } + } + mLastCameraIntent = cameraIntent; if (mCameraPreview != null) { - mPreviewContainer.addView(mCameraPreview); mCameraPreview.setVisibility(View.GONE); } } @@ -779,6 +791,10 @@ private void startFinishDozeAnimationElement(View element, long delay) { .setDuration(DOZE_ANIMATION_ELEMENT_DURATION); } + public void cleanup() { + removeKeyguardBottomArea(); + } + private final class DevicePolicyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 6f0f72039e154..d992b171c5c99 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -88,7 +88,15 @@ public void show(boolean resetSecuritySelection) { if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) { return; } - mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE); + // ensure external keyguard view does not have focus + mPhoneStatusBar.unfocusKeyguardExternalView(); + mPhoneStatusBar.getScrimController().forceHideScrims(false); + // Don't hide bottom area if we are in the middle of a affordance + // launch transition, since once the animation is finished, NPV + // will take care of setting it invisible. + if (!mPhoneStatusBar.mNotificationPanel.isLaunchTransitionRunning()) { + mPhoneStatusBar.mKeyguardBottomArea.setVisibility(View.GONE); + } // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole // Keyguard. If we need to authenticate, show the bouncer. if (!mKeyguardView.dismiss()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java index 8e58d14a6e14f..cf396556881a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -61,7 +61,8 @@ public LockIcon(Context context, AttributeSet attrs) { @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - if (isShown()) { + if (isShown() && + KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive()) { mTrustDrawable.start(); } else { mTrustDrawable.stop(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java index e767ca52a9058..2028132cadbf1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarInsetLayout.java @@ -63,6 +63,7 @@ protected void onDetachedFromWindow() { public NavBarInsetLayout(Context context, AttributeSet attrs) { super(context, attrs); + setMotionEventSplittingEnabled(false); mTransparentSrcPaint.setColor(0); mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index f1820b3baf978..a105f24dc8b03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -77,10 +77,13 @@ import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.LiveLockScreenController; +import com.android.systemui.statusbar.policy.WeatherController; +import com.android.systemui.statusbar.policy.WeatherControllerImpl; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.stack.StackStateAnimator; import cyanogenmod.providers.CMSettings; +import cyanogenmod.weather.util.WeatherUtils; import java.util.List; @@ -88,7 +91,7 @@ public class NotificationPanelView extends PanelView implements ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener, View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener, - HeadsUpManager.OnHeadsUpChangedListener { + HeadsUpManager.OnHeadsUpChangedListener, WeatherController.Callback { private static final boolean DEBUG = false; @@ -106,6 +109,8 @@ public class NotificationPanelView extends PanelView implements private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1); + private static final long SLIDE_PANEL_IN_ANIMATION_DURATION = 300; + public static final long DOZE_ANIMATION_DURATION = 700; @@ -256,11 +261,17 @@ public void run() { private SwipeLockedDirection mLockedDirection; private SwipeHelper mSwipeHelper; - public boolean mShowingExternalKeyguard; private final int mMinimumFlingVelocity; private final int mScreenHeight; private LiveLockScreenController mLiveLockscreenController; private final GestureDetector mGestureDetector; + private ViewLinker mViewLinker; + private final UnlockMethodCache mUnlockMethodCache; + private boolean mDetailScrollLock; + + private boolean mKeyguardWeatherEnabled; + private TextView mKeyguardWeatherInfo; + private WeatherControllerImpl mWeatherController; private enum SwipeLockedDirection { UNKNOWN, @@ -272,12 +283,12 @@ private enum SwipeLockedDirection { SwipeHelper.SimpleCallback mSwipeCallback = new SwipeHelper.SimpleCallback() { @Override public View getChildAtPosition(MotionEvent ev) { - return mNotificationStackScroller; + return mViewLinker.getParent(); } @Override public View getChildContentView(View v) { - return mNotificationStackScroller; + return mViewLinker.getParent(); } @Override @@ -287,7 +298,6 @@ public boolean canChildBeDismissed(View v) { @Override public void onChildDismissed(View v) { - mShowingExternalKeyguard = true; mCanDismissKeyguard = false; mStatusBar.focusKeyguardExternalView(); mLiveLockscreenController.onLiveLockScreenFocusChanged(true /* hasFocus */); @@ -309,10 +319,10 @@ public boolean updateSwipeProgress(View animView, boolean dismissable, float swi mLiveLockscreenController.getLiveLockScreenView() .onLockscreenSlideOffsetChanged(swipeProgress); - // Ensures the status view and notifications are kept in sync when - // being swiped away - mKeyguardStatusView.setTranslationX(mNotificationStackScroller.getTranslationX()); - mKeyguardStatusView.setAlpha(mNotificationStackScroller.getAlpha()); + // Fade out scrim background + float alpha = ScrimController.SCRIM_BEHIND_ALPHA_KEYGUARD - (1f - swipeProgress); + alpha = Math.max(0, alpha); + mStatusBar.getScrimController().setScrimBehindColor(alpha); return false; } @@ -345,7 +355,7 @@ public boolean onDoubleTap(MotionEvent e) { final int gradientEnd = res.getColor(R.color.live_lockscreen_gradient_end); mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { - public float mDown; + private float mDown; @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { @@ -354,7 +364,6 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve return false; } mCanDismissKeyguard = true; - mShowingExternalKeyguard = false; mStatusBar.showBouncer(); return true; } @@ -362,6 +371,7 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float delta = mDown - e2.getRawY(); + delta = Math.max(0, delta); float screenHeightHalf = (float) mScreenHeight / 2f; int color = (Integer) ArgbEvaluator.getInstance() .evaluate(delta / screenHeightHalf, gradientStart, gradientEnd); @@ -389,6 +399,7 @@ public boolean onDown(MotionEvent e) { Point point = new Point(); display.getSize(point); mScreenHeight = point.y; + mUnlockMethodCache = UnlockMethodCache.getInstance(context); } public void setStatusBar(PhoneStatusBar bar) { @@ -399,6 +410,11 @@ public void setLiveController(LiveLockScreenController liveController) { mLiveLockscreenController = liveController; } + public void setWeatherController(WeatherControllerImpl weatherController) { + mWeatherController = weatherController; + mWeatherController.addCallback(this); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -408,6 +424,7 @@ protected void onFinishInflate() { mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view); mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container); mQsPanel = (QSDragPanel) findViewById(R.id.quick_settings_panel); + mQsPanel.setPanelView(this); mClockView = (TextView) findViewById(R.id.clock_view); mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view); mScrollView.setFocusable(false); @@ -427,6 +444,11 @@ protected void onFinishInflate() { mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(), android.R.interpolator.linear_out_slow_in); + mViewLinker = new ViewLinker(mNotificationStackScroller, + new ViewLinker.LinkInfo(mKeyguardStatusBar, ViewLinker.LINK_ALPHA), + new ViewLinker.LinkInfo(mKeyguardStatusView, ViewLinker.LINK_ALPHA + | ViewLinker.LINK_TRANSLATION)); + mKeyguardBottomArea = (KeyguardBottomAreaView) View.inflate(getContext(), R.layout.keyguard_bottom_area, null); /** Keyguard bottom area lives in a separate window, and as such, @@ -435,15 +457,16 @@ protected void onFinishInflate() { mKeyguardBottomArea.setOnInterceptTouchListener(new KeyguardBottomAreaView.OnInterceptTouchEventListener() { @Override public boolean onInterceptTouchEvent(MotionEvent e) { - boolean intercept = mAfforanceHelper.onInterceptTouchEvent(e); - if (!intercept) { - if (mShowingExternalKeyguard) { - // Handles swipe up to fade/dismiss when showing - // live lock screen + boolean intercept = false; + if (mLiveLockscreenController.getLiveLockScreenHasFocus()) { + // Handles swipe up to fade/dismiss when showing + // live lock screen + intercept = mAfforanceHelper.onInterceptTouchEvent(e); + if (!intercept) { intercept = mGestureDetector.onTouchEvent(e); - } else { - intercept = NotificationPanelView.this.onInterceptTouchEvent(e); } + } else { + intercept = NotificationPanelView.this.onInterceptTouchEvent(e); } return intercept; } @@ -452,19 +475,27 @@ public boolean onInterceptTouchEvent(MotionEvent e) { @Override public boolean onTouch(View v, MotionEvent e) { int action = e.getAction(); - // Ensure we collapse and clear fade - if (action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_CANCEL) { + + boolean isCancelOrUp = action == MotionEvent.ACTION_UP || + action == MotionEvent.ACTION_CANCEL; + if (isCancelOrUp) { mKeyguardBottomArea.setBackground(null); } - boolean intercept = mAfforanceHelper.onTouchEvent(e); - if (!intercept) { - if (mShowingExternalKeyguard) { + boolean intercept = false; + if (mLiveLockscreenController.getLiveLockScreenHasFocus()) { + intercept = mAfforanceHelper.onTouchEvent(e); + // If the touch did not originate on the affordance helper, + // we must collapse the panel here since we can't rely on + // the swipe callbacks from being invoked. + if (isCancelOrUp && !isAffordanceSwipeInProgress()) { + mKeyguardBottomArea.expand(false); + } + if (!intercept) { intercept = mGestureDetector.onTouchEvent(e); - } else { - intercept = NotificationPanelView.this.onTouchEvent(e); } + } else { + intercept = NotificationPanelView.this.onTouchEvent(e); } return intercept; } @@ -486,6 +517,12 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom, } } }); + + mKeyguardWeatherInfo = (TextView) mKeyguardStatusView.findViewById(R.id.weather_info); + } + + public boolean isAffordanceSwipeInProgress() { + return mAfforanceHelper.isSwipingInProgress(); } @Override @@ -499,6 +536,7 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mSettingsObserver.unobserve(); + mWeatherController.removeCallback(this); } @Override @@ -804,7 +842,8 @@ public boolean onInterceptTouchEvent(MotionEvent event) { return true; } - if (isKeyguardInteractiveAndShowing()) { + if (isKeyguardInteractiveAndShowing() || mStatusBar.isKeyguardShowingMedia() || + (mUnlockMethodCache.isTrustManaged() && mAfforanceHelper.isOnLockIcon(event))) { return super.onInterceptTouchEvent(event); } @@ -984,7 +1023,8 @@ public boolean onTouchEvent(MotionEvent event) { } if ((!mIsExpanding || mHintAnimationRunning) && !mQsExpanded - && mStatusBar.getBarState() != StatusBarState.SHADE) { + && (mStatusBar.getBarState() != StatusBarState.SHADE + || mLiveLockscreenController.getLiveLockScreenHasFocus())) { mAfforanceHelper.onTouchEvent(event); } if (mOnlyAffordanceInThisMotion) { @@ -999,30 +1039,35 @@ public boolean onTouchEvent(MotionEvent event) { updateVerticalPanelPosition(event.getX()); } - if (isKeyguardInteractiveAndShowing()) { + if (isKeyguardInteractiveAndShowing() || mStatusBar.isKeyguardShowingMedia() || + (mUnlockMethodCache.isTrustManaged() && mAfforanceHelper.isOnLockIcon(event))) { super.onTouchEvent(event); return true; } - if (!mSwipeHelper.isDragging() && super.onTouchEvent(event)) { - mLockedDirection = SwipeLockedDirection.VERTICAL; - return true; - } - if ((!mIsExpanding || mHintAnimationRunning) && !mQsExpanded && mLockedDirection != SwipeLockedDirection.VERTICAL && mStatusBar.getBarState() != StatusBarState.SHADE) { - if (mSwipeHelper.onTouchEvent(event)) { + mSwipeHelper.onTouchEvent(event); + if (mSwipeHelper.isDragging()) { mLockedDirection = SwipeLockedDirection.HORIZONTAL; + } + if (mLockedDirection == SwipeLockedDirection.HORIZONTAL) { + requestDisallowInterceptTouchEvent(true); return true; } } - return false; + + if (super.onTouchEvent(event)) { + mLockedDirection = SwipeLockedDirection.VERTICAL; + } + return true; } private boolean isKeyguardInteractiveAndShowing() { - return mShowingExternalKeyguard || mStatusBar.getBarState() != StatusBarState.KEYGUARD || + return mLiveLockscreenController.getLiveLockScreenHasFocus() || + mStatusBar.getBarState() != StatusBarState.KEYGUARD || !mLiveLockscreenController.isLiveLockScreenInteractive(); } @@ -1057,7 +1102,8 @@ private boolean handleQsTouch(MotionEvent event) { mTwoFingerQsExpandPossible = true; } if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) - && event.getY(event.getActionIndex()) < mStatusBarMinHeight) { + && event.getY(event.getActionIndex()) < mStatusBarMinHeight + && mExpandedHeight <= mQsPeekHeight) { MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1); mQsExpandImmediate = true; requestPanelHeightUpdate(); @@ -1197,8 +1243,13 @@ private void onQsTouch(MotionEvent event) { mTrackingPointer = -1; trackMovement(event); float fraction = getQsExpansionFraction(); - if ((fraction != 0f || y >= mInitialTouchY) - && (fraction != 1f || y <= mInitialTouchY)) { + final boolean fling = (fraction != 0f || y >= mInitialTouchY) + && (fraction != 1f || y <= mInitialTouchY); + final boolean flingExpand = Math.abs(getCurrentVelocity()) + > mFlingAnimationUtils.getMinVelocityPxPerSecond(); + final boolean detailFling = mDetailScrollLock && mQsExpanded + && flingExpand; + if ((fling && !mDetailScrollLock) || detailFling) { flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL); } else { @@ -1299,7 +1350,9 @@ public void setBarState(int statusBarState, boolean keyguardFadingAway, mStatusBarState = statusBarState; mKeyguardShowing = keyguardShowing; - mCanDismissKeyguard = keyguardShowing; + if (oldState != statusBarState && statusBarState == StatusBarState.KEYGUARD) { + mCanDismissKeyguard = true; + } if (goingToFullShade || (oldState == StatusBarState.KEYGUARD && statusBarState == StatusBarState.SHADE_LOCKED)) { @@ -1776,7 +1829,8 @@ private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) { && y >= header.getTop() && y <= header.getBottom(); if (mQsExpanded) { - return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y); + return onHeader || mDetailScrollLock + || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y); } else { return onHeader; } @@ -1846,11 +1900,6 @@ protected void onHeightUpdated(float expandedHeight) { updateNotificationTranslucency(); updatePanelExpanded(); mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed()); - if (mShowingExternalKeyguard && expandedHeight >= getMaxPanelHeight()) { - mStatusBar.unfocusKeyguardExternalView(); - mLiveLockscreenController.onLiveLockScreenFocusChanged(false /* hasFocus */); - mShowingExternalKeyguard = false; - } if (DEBUG) { invalidate(); } @@ -1871,7 +1920,7 @@ private void updatePanelExpanded() { */ private int getTempQsMaxExpansion() { int qsTempMaxExpansion = mQsMaxExpansionHeight; - if (mScrollYOverride != -1) { + if (mScrollYOverride != -1 && !mDetailScrollLock) { qsTempMaxExpansion -= mScrollYOverride; } return qsTempMaxExpansion; @@ -2026,9 +2075,6 @@ private float getKeyguardContentsAlpha() { alpha = getNotificationsTopY() / (mKeyguardStatusBar.getHeight() + mNotificationsHeaderCollideDistance); - } else if (mStatusBar.getBarState() == StatusBarState.SHADE && - mLiveLockscreenController.isShowingLiveLockScreenView()) { - alpha = 1; } else { // In SHADE_LOCKED, the top card is already really close to the header. Hide it as @@ -2041,6 +2087,9 @@ private float getKeyguardContentsAlpha() { } private void updateHeaderKeyguardAlpha() { + if (mSwipeHelper.isDragging()) { + return; + } float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2); mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion) * mKeyguardStatusBarAnimateAlpha); @@ -2055,6 +2104,9 @@ private void updateHeaderKeyguard() { private void updateKeyguardBottomAreaAlpha() { float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction()); + if (mLiveLockscreenController.getLiveLockScreenHasFocus()) { + alpha = 1f; + } mKeyguardBottomArea.setAlpha(alpha); mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS @@ -2278,6 +2330,7 @@ public void onAnimationToSideEnded() { mLaunchAnimationEndRunnable.run(); mLaunchAnimationEndRunnable = null; } + mKeyguardBottomArea.setVisibility(View.GONE); } @Override @@ -2332,6 +2385,7 @@ public void onIconClicked(boolean rightIcon) { return; } mHintAnimationRunning = true; + mKeyguardBottomArea.expand(true); mAfforanceHelper.startHintAnimation(rightIcon, new Runnable() { @Override public void run() { @@ -2512,11 +2566,6 @@ private void updateEmptyShadeView() { // Hide "No notifications" in QS. mNotificationStackScroller.updateEmptyShadeView(mShadeEmpty && !mQsExpanded); - if (mStatusBarState == StatusBarState.KEYGUARD - && (!mQsExpanded || mQsExpandImmediate || mIsExpanding - && mQsExpandedWhenExpandingStarted)) { - positionClockAndNotifications(); - } } public void setQsScrimEnabled(boolean qsScrimEnabled) { @@ -2716,6 +2765,8 @@ void observe() { CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN), false, this); resolver.registerContentObserver(CMSettings.System.getUriFor( CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this); + resolver.registerContentObserver(CMSettings.Secure.getUriFor( + CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED), false, this); update(); } @@ -2741,8 +2792,13 @@ public void update() { mDoubleTapToSleepEnabled = CMSettings.System.getInt( resolver, CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE, 1) == 1; - boolean liveLockScreenEnabled = CMSettings.Secure.getInt( - resolver, CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED, 0) == 1; + boolean wasKeyguardWeatherEnabled = mKeyguardWeatherEnabled; + mKeyguardWeatherEnabled = CMSettings.Secure.getInt( + resolver, CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 0) == 1; + if (mWeatherController != null + && wasKeyguardWeatherEnabled != mKeyguardWeatherEnabled) { + onWeatherChanged(mWeatherController.getWeatherInfo()); + } } } @@ -2756,6 +2812,8 @@ public void launchCamera(boolean animate, int source) { mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP; } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) { mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE; + } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE) { + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_SCREEN_GESTURE; } else { // Default. @@ -2765,7 +2823,8 @@ public void launchCamera(boolean animate, int source) { // If we are launching it when we are occluded already we don't want it to animate, // nor setting these flags, since the occluded state doesn't change anymore, hence it's // never reset. - if (!isFullyCollapsed()) { + if (!isFullyCollapsed() && mLastCameraLaunchSource == + KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE) { mLaunchingAffordance = true; setLaunchingAffordance(true); } else { @@ -2814,7 +2873,106 @@ private boolean isForegroundApp(String pkgName) { return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); } - public void slideLockScreenOut() { - mSwipeCallback.onChildDismissed(this); + public void setDetailRequestedScrollLock(boolean detailScrollFlag) { + if (mDetailScrollLock != detailScrollFlag) { + if (mStatusBarState != StatusBarState.SHADE) { + mDetailScrollLock = false; + } else { + mDetailScrollLock = detailScrollFlag; + } + if (!detailScrollFlag && getQsExpansionFraction() > 0.3f) { + flingSettings(getCurrentVelocity(), true, new Runnable() { + @Override + public void run() { + mStackScrollerOverscrolling = false; + mQsExpansionFromOverscroll = false; + updateQsState(); + updateHeader(); + updateMaxHeadsUpTranslation(); + updatePanelExpanded(); + requestLayout(); + } + }, false); + } else { + requestLayout(); + } + } + } + + @Override + public void onWeatherChanged(WeatherController.WeatherInfo info) { + if (!mKeyguardWeatherEnabled || Double.isNaN(info.temp) || info.condition == null) { + mKeyguardWeatherInfo.setVisibility(GONE); + } else { + mKeyguardWeatherInfo.setText(mContext.getString( + R.string.keyguard_status_view_weather_format, + WeatherUtils.formatTemperature(info.temp, info.tempUnit), + info.condition)); + mKeyguardWeatherInfo.setVisibility(VISIBLE); + } + } + + private class SlideInAnimationListener implements ValueAnimator.AnimatorUpdateListener, + ValueAnimator.AnimatorListener { + @Override + public void onAnimationStart(Animator animator) {} + + @Override + public void onAnimationEnd(Animator animator) { + animationFinished(animator); + } + + @Override + public void onAnimationCancel(Animator animator) { + animationFinished(animator); + } + + @Override + public void onAnimationRepeat(Animator animator) {} + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + View statusBarView = mStatusBar.getStatusBarWindow(); + if (valueAnimator.getAnimatedFraction() > 0 && + statusBarView.getVisibility() != View.VISIBLE) { + statusBarView.setVisibility(View.VISIBLE); + } + float translationX = (Float) valueAnimator.getAnimatedValue(); + float alpha = valueAnimator.getAnimatedFraction(); + + mViewLinker.getParent().setTranslationX(translationX); + mViewLinker.getParent().setAlpha(alpha); + + float alpha1 = ScrimController.SCRIM_BEHIND_ALPHA_KEYGUARD * alpha; + alpha1 = Math.max(0, alpha1); + mStatusBar.getScrimController().setScrimBehindColor(alpha1); + mLiveLockscreenController.getLiveLockScreenView() + .onLockscreenSlideOffsetChanged(alpha); + } + + private void animationFinished(Animator animator) { + mLiveLockscreenController.onLiveLockScreenFocusChanged(false); + } + } + + private SlideInAnimationListener mSlideInAnimationListener = new SlideInAnimationListener(); + + public void slideLockScreenIn() { + mNotificationStackScroller.setVisibility(View.VISIBLE); + mNotificationStackScroller.setAlpha(0f); + mNotificationStackScroller.setTranslationX(-mNotificationStackScroller.getWidth()); + mKeyguardStatusView.setVisibility(View.VISIBLE); + mKeyguardStatusView.setAlpha(0f); + mKeyguardStatusView.setTranslationX(mNotificationStackScroller.getTranslationX()); + mKeyguardStatusBar.setAlpha(0f); + + mStatusBar.getScrimController().setScrimBehindColor(0f); + ValueAnimator animator = ValueAnimator.ofFloat( + mNotificationStackScroller.getTranslationX(), + 0f); + animator.setDuration(SLIDE_PANEL_IN_ANIMATION_DURATION); + animator.addUpdateListener(mSlideInAnimationListener); + animator.addListener(mSlideInAnimationListener); + animator.start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index e5711b89cd010..ae565edfd1943 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -94,7 +94,7 @@ private final void logf(String fmt, Object... args) { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { // update expand height - if (mHeightAnimator != null && mExpanding && mUpdateExpandOnLayout) { + if (mHeightAnimator != null && mExpanding && mUpdateExpandOnLayout && !mJustPeeked) { final int maxPanelHeight = getMaxPanelHeight(); final PropertyValuesHolder[] values = mHeightAnimator.getValues(); values[0].setFloatValues(maxPanelHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 661232fb2cd22..39ef494aff60d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -106,6 +106,7 @@ import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; +import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -325,7 +326,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, StatusBarWindowView mStatusBarWindow; FrameLayout mStatusBarWindowContent; - PhoneStatusBarView mStatusBarView; + private PhoneStatusBarView mStatusBarView; private int mStatusBarWindowState = WINDOW_STATE_SHOWING; private StatusBarWindowManager mStatusBarWindowManager; private UnlockMethodCache mUnlockMethodCache; @@ -493,6 +494,10 @@ public void update() { } } + public void setStatusBarViewVisibility(boolean visible) { + mStatusBarView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + } + class DevForceNavbarObserver extends UserContentObserver { DevForceNavbarObserver(Handler handler) { super(handler); @@ -502,14 +507,14 @@ class DevForceNavbarObserver extends UserContentObserver { protected void observe() { super.observe(); ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(CMSettings.Secure.getUriFor( - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(CMSettings.Global.getUriFor( + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL); } @Override public void update() { - boolean visible = CMSettings.Secure.getIntForUser(mContext.getContentResolver(), - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; + boolean visible = CMSettings.Global.getIntForUser(mContext.getContentResolver(), + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; if (visible) { forceAddNavigationBar(); @@ -788,6 +793,10 @@ public void onClick(View v) { private RankingMap mLatestRankingMap; private boolean mNoAnimationOnNextBarModeChange; + public ScrimController getScrimController() { + return mScrimController; + } + @Override public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) @@ -878,9 +887,8 @@ protected PhoneStatusBarView makeStatusBarView() { Resources res = context.getResources(); - mScreenWidth = (float) context.getResources().getDisplayMetrics().widthPixels; - mMinBrightness = context.getResources().getInteger( - com.android.internal.R.integer.config_screenBrightnessDim); + mScreenWidth = (float) res.getDisplayMetrics().widthPixels; + mMinBrightness = res.getInteger(com.android.internal.R.integer.config_screenBrightnessDim); updateDisplaySize(); // populates mDisplayMetrics updateResources(null); @@ -919,6 +927,9 @@ public boolean onTouch(View v, MotionEvent event) { mLiveLockScreenController = new LiveLockScreenController(mContext, this, mNotificationPanel); mNotificationPanel.setLiveController(mLiveLockScreenController); + if (mStatusBarWindowManager != null) { + mStatusBarWindowManager.setLiveLockscreenController(mLiveLockScreenController); + } if (mHeadsUpManager == null) { mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow); @@ -1317,6 +1328,8 @@ public void run() { mHeader.setNextAlarmController(mNextAlarmController); mHeader.setWeatherController(mWeatherController); + mNotificationPanel.setWeatherController(mWeatherController); + PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBroadcastReceiver.onReceive(mContext, new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); @@ -1488,7 +1501,7 @@ public void onCustomTilePosted(final StatusBarPanelCustomTile sbc) { @Override public void run() { boolean isUpdate = mQSPanel.getHost().getCustomTileData() - .get(sbc.getKey()) != null; + .get(sbc.persistableKey()) != null; if (isUpdate) { mQSPanel.getHost().updateCustomTile(sbc); } else { @@ -1504,7 +1517,7 @@ public void onCustomTileRemoved(final StatusBarPanelCustomTile sbc) { mHandler.post(new Runnable() { @Override public void run() { - mQSPanel.getHost().removeCustomTileSysUi(sbc.getKey()); + mQSPanel.getHost().removeCustomTileSysUi(sbc.persistableKey()); } }); } @@ -2957,7 +2970,7 @@ public boolean interceptTouchEvent(MotionEvent event) { setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true); } } - if (mBrightnessChanged && upOrCancel) { + if (mBrightnessChanged && upOrCancel && !isQsExpanded()) { mBrightnessChanged = false; if (mJustPeeked && mExpandedVisible) { mNotificationPanel.fling(10, false); @@ -3452,6 +3465,9 @@ private void addStatusBarWindow() { mStatusBarWindowManager = new StatusBarWindowManager(mContext, mKeyguardMonitor); mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); + if (mLiveLockScreenController != null) { + mStatusBarWindowManager.setLiveLockscreenController(mLiveLockScreenController); + } } // called by makeStatusbar and also by PhoneStatusBarView @@ -3707,6 +3723,12 @@ public void userSwitched(int newUserId) { } } + public void hideHeadsUp() { + if (mUseHeadsUp && mHeadsUpManager != null) { + mHeadsUpManager.releaseAllImmediately(); + } + } + private void setControllerUsers() { if (mZenModeController != null) { mZenModeController.setUserId(mCurrentUserId); @@ -3778,6 +3800,7 @@ private void recreateStatusBar() { mLiveLockScreenController.cleanup(); } + mKeyguardBottomArea.cleanup(); mStatusBarWindow.removeContent(mStatusBarWindowContent); mStatusBarWindow.clearDisappearingChildren(); @@ -3882,7 +3905,9 @@ private void removeAllViews(ViewGroup parent) { removeAllViews((ViewGroup) child); } } - parent.removeAllViews(); + + // AdapterView does not support removeAllViews so check before calling + if (!(parent instanceof AdapterView)) parent.removeAllViews(); } /** @@ -4335,7 +4360,15 @@ public void showKeyguard() { mDraggedDownRow = null; } mAssistManager.onLockscreenShown(); + mKeyguardBottomArea.requestFocus(); + try { + WindowManagerGlobal.getWindowManagerService() + .setLiveLockscreenEdgeDetector(false); + } catch (RemoteException e){ + e.printStackTrace(); + } if (mLiveLockScreenController.isShowingLiveLockScreenView()) { + mLiveLockScreenController.onLiveLockScreenFocusChanged(false); mLiveLockScreenController.getLiveLockScreenView().onKeyguardShowing( mStatusBarKeyguardViewManager.isScreenTurnedOn()); } @@ -4505,6 +4538,10 @@ boolean isSecure() { return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isSecure(); } + public boolean isKeyguardInputRestricted() { + return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isInputRestricted(); + } + public long calculateGoingToFullShadeDelay() { return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration; } @@ -4670,7 +4707,8 @@ public boolean onSpacePressed() { } public void showBouncer() { - if (!mRecreating && mNotificationPanel.mCanDismissKeyguard) { + if (!mRecreating && mNotificationPanel.mCanDismissKeyguard + && (mState != StatusBarState.SHADE || mLiveLockScreenController.getLiveLockScreenHasFocus())) { mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing(); mStatusBarKeyguardViewManager.dismiss(); } @@ -4686,7 +4724,6 @@ protected void showBouncerOrFocusKeyguardExternalView() { } protected void unfocusKeyguardExternalView() { - setBarState(StatusBarState.KEYGUARD); mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false); } @@ -4775,14 +4812,10 @@ public void onLeftHintStarted(String hint) { } public void onTrackingStopped(boolean expand) { - if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED || mStatusBarWindowManager.keyguardExternalViewHasFocus()) { - if (!expand && (!mUnlockMethodCache.canSkipBouncer() || - mLiveLockScreenController.isShowingLiveLockScreenView())) { + if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { + if (!expand && !mUnlockMethodCache.canSkipBouncer()) { showBouncer(); } - } else if (expand && mStatusBarWindowManager.keyguardExternalViewHasFocus()) { - mStatusBarKeyguardViewManager.setKeyguardExternalViewFocus(false); - setBarState(StatusBarState.KEYGUARD); } } @@ -5372,6 +5405,10 @@ public boolean isShowingLiveLockScreenView() { return mLiveLockScreenController.isShowingLiveLockScreenView(); } + public void slideNotificationPanelIn() { + mNotificationPanel.slideLockScreenIn(); + } + private final class ShadeUpdates { private final ArraySet mVisibleNotifications = new ArraySet(); private final ArraySet mNewVisibleNotifications = new ArraySet(); @@ -5524,4 +5561,8 @@ public void handleMessage(Message msg) { } } } + + public boolean isAffordanceSwipeInProgress() { + return mNotificationPanel.isAffordanceSwipeInProgress(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 3b068d673871e..8c9daeefd640e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -111,6 +111,7 @@ public PanelView selectPanelForTouch(MotionEvent touch) { @Override public void onPanelPeeked() { super.onPanelPeeked(); + removePendingHideExpandedRunnables(); mBar.makeExpandedVisible(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 2c68c62667f74..53310dda39c74 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -372,7 +372,12 @@ public QSTile createTile(String tileSpec) { else if (tileSpec.equals("battery_saver")) return new BatterySaverTile(this); else if (tileSpec.equals("caffeine")) return new CaffeineTile(this); else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec); - else throw new IllegalArgumentException("Bad tile spec: " + tileSpec); + else if (TextUtils.split(tileSpec, "\\|").length == 3) { + /** restores placeholder for + * {@link cyanogenmod.app.StatusBarPanelCustomTile#persistableKey()} **/ + return new CustomQSTile(this, tileSpec); + } else + throw new IllegalArgumentException("Bad tile spec: " + tileSpec); } protected List loadTileSpecs(String tileList) { @@ -498,8 +503,8 @@ public static int getIconResource(String spec) { void updateCustomTile(StatusBarPanelCustomTile sbc) { synchronized (mTiles) { - if (mTiles.containsKey(sbc.getKey())) { - QSTile tile = mTiles.get(sbc.getKey()); + if (mTiles.containsKey(sbc.persistableKey())) { + QSTile tile = mTiles.get(sbc.persistableKey()); if (tile instanceof CustomQSTile) { CustomQSTile qsTile = (CustomQSTile) tile; qsTile.update(sbc); @@ -511,8 +516,8 @@ void updateCustomTile(StatusBarPanelCustomTile sbc) { void addCustomTile(StatusBarPanelCustomTile sbc) { synchronized (mTiles) { mCustomTileData.add(new CustomTileData.Entry(sbc)); - mTileSpecs.add(sbc.getKey()); - mTiles.put(sbc.getKey(), new CustomQSTile(this, sbc)); + mTileSpecs.add(sbc.persistableKey()); + mTiles.put(sbc.persistableKey(), new CustomQSTile(this, sbc)); if (mCallback != null) { mCallback.onTilesChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index b9e92928992fa..975cb77fdd933 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -45,9 +45,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, public static final long ANIMATION_DURATION = 220; public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR = new PathInterpolator(0f, 0, 0.7f, 1f); + public static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f; private static final float SCRIM_BEHIND_ALPHA = 0.62f; - private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f; private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f; private static final float SCRIM_IN_FRONT_ALPHA = 0.75f; private static final int TAG_KEY_ANIM = R.id.scrim; @@ -255,7 +255,7 @@ private void updateScrimNormal() { } } - private void setScrimBehindColor(float alpha) { + public void setScrimBehindColor(float alpha) { setScrimColor(mScrimBehind, alpha); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 339d4697cbe1a..f9b1f38c8f33b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -76,6 +76,7 @@ import cyanogenmod.app.StatusBarPanelCustomTile; import cyanogenmod.providers.CMSettings; +import cyanogenmod.weather.util.WeatherUtils; import org.cyanogenmod.internal.logging.CMMetricsLogger; /** @@ -280,6 +281,10 @@ protected void onConfigurationChanged(Configuration newConfig) { mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size); mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize; + if (mEditTileDoneText != null) { + mEditTileDoneText.setText(R.string.quick_settings_done); + } + updateClockScale(); updateClockCollapsedMargin(); } @@ -515,12 +520,12 @@ public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { @Override public void onWeatherChanged(WeatherController.WeatherInfo info) { - if (info.temp == null || info.condition == null) { + if (Double.isNaN(info.temp) || info.condition == null) { mWeatherLine1.setText(null); } else { mWeatherLine1.setText(mContext.getString( R.string.status_bar_expanded_header_weather_format, - info.temp, + WeatherUtils.formatTemperature(info.temp, info.tempUnit), info.condition)); } mWeatherLine2.setText(info.city); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index 9a991f4bf0bc4..96a496021548f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -19,10 +19,12 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; +import android.database.ContentObserver; import android.graphics.Point; import android.graphics.PixelFormat; +import android.os.Handler; import android.os.SystemProperties; -import android.util.Log; +import android.provider.Settings; import android.view.Gravity; import android.view.Display; import android.view.SurfaceSession; @@ -35,8 +37,8 @@ import com.android.systemui.statusbar.BaseStatusBar; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.statusbar.policy.LiveLockScreenController; import cyanogenmod.providers.CMSettings; -import org.cyanogenmod.internal.util.CmLockPatternUtils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -53,8 +55,9 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback { private WindowManager.LayoutParams mLp; private WindowManager.LayoutParams mLpChanged; private int mBarHeight; - private final boolean mKeyguardScreenRotation; + private boolean mKeyguardScreenRotation; private final float mScreenBrightnessDoze; + private final boolean mBlurSupported; private boolean mKeyguardBlurEnabled; private boolean mShowingMedia; @@ -69,6 +72,7 @@ public class StatusBarWindowManager implements KeyguardMonitor.Callback { private static final int STATUS_BAR_LAYER = 16 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; private final State mCurrentState = new State(); + private LiveLockScreenController mLiveLockScreenController; public StatusBarWindowManager(Context context, KeyguardMonitor kgm) { mContext = context; @@ -76,18 +80,23 @@ public StatusBarWindowManager(Context context, KeyguardMonitor kgm) { mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); mScreenBrightnessDoze = mContext.getResources().getInteger( com.android.internal.R.integer.config_screenBrightnessDoze) / 255f; + mBlurSupported = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_ui_blur_enabled); mKeyguardMonitor = kgm; mKeyguardMonitor.addCallback(this); - mKeyguardBlurEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_ui_blur_enabled); mFxSession = new SurfaceSession(); } private boolean shouldEnableKeyguardScreenRotation() { Resources res = mContext.getResources(); + boolean enableAccelerometerRotation = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.ACCELEROMETER_ROTATION, 1) != 0; + boolean enableLockScreenRotation = CMSettings.System.getInt(mContext.getContentResolver(), + CMSettings.System.LOCKSCREEN_ROTATION, 0) != 0; return SystemProperties.getBoolean("lockscreen.rot_override", false) - || res.getBoolean(R.bool.config_enableLockScreenRotation); + || (res.getBoolean(R.bool.config_enableLockScreenRotation) + && (enableLockScreenRotation && enableAccelerometerRotation)); } /** @@ -121,7 +130,10 @@ public void add(View statusBarView, int barHeight) { mLpChanged = new WindowManager.LayoutParams(); mLpChanged.copyFrom(mLp); - if (mKeyguardBlurEnabled) { + mKeyguardBlurEnabled = mBlurSupported ? + CMSettings.Secure.getInt(mContext.getContentResolver(), + CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED, 1) == 1 : false; + if (mBlurSupported) { Display display = mWindowManager.getDefaultDisplay(); Point xy = new Point(); display.getRealSize(xy); @@ -130,6 +142,9 @@ public void add(View statusBarView, int barHeight) { mKeyguardBlur.setLayer(STATUS_BAR_LAYER - 2); } } + + SettingsObserver observer = new SettingsObserver(new Handler()); + observer.observe(mContext); } private void applyKeyguardFlags(State state) { @@ -141,7 +156,7 @@ private void applyKeyguardFlags(State state) { } else { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; - if (mKeyguardBlurEnabled) { + if (mKeyguardBlurEnabled && mKeyguardBlur != null) { mKeyguardBlur.hide(); } } @@ -260,8 +275,7 @@ private void applyKeyguardBlurShow(){ boolean isblur = false; if (mCurrentState.keyguardShowing && mKeyguardBlurEnabled && !mCurrentState.keyguardOccluded - && !mShowingMedia - && !isShowingLiveLockScreen()) { + && !mShowingMedia) { isblur = true; } if (mKeyguardBlur != null) { @@ -341,7 +355,7 @@ public void setShowingMedia(boolean showingMedia) { } public void setKeyguardExternalViewFocus(boolean hasFocus) { - mCurrentState.keyguardExternalViewHasFocus = hasFocus; + mLiveLockScreenController.onLiveLockScreenFocusChanged(hasFocus); // make the keyguard occluded so the external view gets full focus setKeyguardOccluded(hasFocus); } @@ -394,14 +408,11 @@ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { } public boolean keyguardExternalViewHasFocus() { - return mCurrentState.keyguardExternalViewHasFocus; + return mLiveLockScreenController.getLiveLockScreenHasFocus(); } - private boolean isShowingLiveLockScreen() { - CmLockPatternUtils lockPatternUtils = new CmLockPatternUtils(mContext); - return (CMSettings.Secure.getInt(mContext.getContentResolver(), - CMSettings.Secure.LIVE_LOCK_SCREEN_ENABLED, 0) == 1) - && lockPatternUtils.isThirdPartyKeyguardEnabled(); + public void setLiveLockscreenController(LiveLockScreenController liveLockScreenController) { + mLiveLockScreenController = liveLockScreenController; } private static class State { @@ -418,7 +429,6 @@ private static class State { boolean forceStatusBarVisible; boolean forceCollapsed; boolean forceDozeBrightness; - boolean keyguardExternalViewHasFocus; /** * The {@link BaseStatusBar} state from the status bar. @@ -455,4 +465,39 @@ public String toString() { return result.toString(); } } + + private class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + } + + public void observe(Context context) { + context.getContentResolver().registerContentObserver( + CMSettings.Secure.getUriFor(CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED), + false, + this); + context.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), + false, + this); + context.getContentResolver().registerContentObserver( + CMSettings.System.getUriFor(CMSettings.System.LOCKSCREEN_ROTATION), + false, + this); + } + + public void unobserve(Context context) { + context.getContentResolver().unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + mKeyguardBlurEnabled = mBlurSupported ? + CMSettings.Secure.getInt(mContext.getContentResolver(), + CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED, 1) == 1 : false; + mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); + // update the state + apply(mCurrentState); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java new file mode 100644 index 0000000000000..48457c6b24f62 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ViewLinker.java @@ -0,0 +1,76 @@ +package com.android.systemui.statusbar.phone; + +import android.view.View; + +/* + Allows mirroring of view states such as alpha, translation...etc + */ +public class ViewLinker { + + public static final int LINK_ALPHA = 0x1; + public static final int LINK_TRANSLATION = 0x2; + + private final LinkInfo[] mLinkedViews; + private final T mParent; + + public interface ViewLinkerCallback { + void onAlphaChanged(float alpha); + void onTranslationXChanged(float translationX); + } + + public interface ViewLinkerParent { + void registerLinker(ViewLinkerCallback callback); + } + + public static class LinkInfo { + private View mView; + private int mFlags; + public LinkInfo(View v, int linkFlags) { + mView = v; + mFlags = linkFlags; + } + private boolean supportsFlag(int flag) { + return (mFlags & flag) != 0; + } + } + + private ViewLinkerCallback mCallback = new ViewLinkerCallback() { + @Override + public void onAlphaChanged(float alpha) { + for (LinkInfo v : mLinkedViews) { + if (v.supportsFlag(LINK_ALPHA)) { + v.mView.setAlpha(alpha); + } + } + } + + @Override + public void onTranslationXChanged(float translationX) { + for (LinkInfo v : mLinkedViews) { + if (v.supportsFlag(LINK_TRANSLATION)) { + v.mView.setTranslationX(translationX); + } + } + } + }; + + public ViewLinker(T parent, LinkInfo... viewsToLink) { + mLinkedViews = viewsToLink; + mParent = parent; + ensureParentNotInLink(); + parent.registerLinker(mCallback); + } + + private void ensureParentNotInLink() { + for (LinkInfo v : mLinkedViews) { + if (v.mView == mParent) { + throw new IllegalStateException("Parent cannot be" + + "one of the linked views"); + } + } + } + + public View getParent() { + return mParent; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java index 1beb886ddc261..ccbe911c736fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LiveLockScreenController.java @@ -10,6 +10,7 @@ import android.os.ServiceManager; import android.util.EventLog; +import android.view.View; import com.android.systemui.EventLogTags; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.NotificationPanelView; @@ -79,6 +80,10 @@ public void setBarState(int statusBarState) { onKeyguardDismissed(); } + if (statusBarState == StatusBarState.KEYGUARD) { + mBar.getScrimController().forceHideScrims(false); + } + mStatusBarState = statusBarState; if (statusBarState == StatusBarState.KEYGUARD || statusBarState == StatusBarState.SHADE_LOCKED) { @@ -97,9 +102,10 @@ public void setBarState(int statusBarState) { } } } else { - if (isShowingLiveLockScreenView()) { + if (isShowingLiveLockScreenView() && !mBar.isKeyguardInputRestricted()) { mPanelView.removeView(mLiveLockScreenView); } + mLlsHasFocus = false; } } @@ -161,7 +167,6 @@ public boolean requestDismissAndStartActivity(final Intent intent) { mHandler.post(new Runnable() { @Override public void run() { - mBar.showKeyguard(); mBar.startActivityDismissingKeyguard(intent, false, true, true, null); } @@ -177,17 +182,20 @@ public void providerDied() { mExternalKeyguardViewCallbacks); mLiveLockScreenView = null; // make sure we're showing the notification panel if the LLS crashed while it had focus - mHandler.post(new Runnable() { - @Override - public void run() { - mBar.showKeyguard(); - } - }); + if (mLlsHasFocus) { + mLlsHasFocus = false; + mHandler.post(new Runnable() { + @Override + public void run() { + mBar.showKeyguard(); + } + }); + } } @Override public void slideLockscreenIn() { - if (mPanelView.mShowingExternalKeyguard) { + if (mLlsHasFocus) { mHandler.post(new Runnable() { @Override public void run() { @@ -229,23 +237,32 @@ public void onScreenTurnedOff() { } public void onLiveLockScreenFocusChanged(boolean hasFocus) { - if (hasFocus != mLlsHasFocus) { - mLlsHasFocus = hasFocus; - if (mLiveLockScreenView != null) { - // make sure the LLS knows where the notification panel is - mLiveLockScreenView.onLockscreenSlideOffsetChanged(hasFocus ? 0f : 1f); - } - // don't log focus changes when screen is not interactive - if (mPowerManager.isInteractive()) { - EventLog.writeEvent(EventLogTags.SYSUI_LLS_NOTIFICATION_PANEL_SHOWN, - hasFocus ? 0 : 1); - } + if (mLiveLockScreenView != null) { + // make sure the LLS knows where the notification panel is + mLiveLockScreenView.onLockscreenSlideOffsetChanged(hasFocus ? 0f : 1f); + } + // don't log focus changes when screen is not interactive + if (hasFocus != mLlsHasFocus && mPowerManager.isInteractive()) { + EventLog.writeEvent(EventLogTags.SYSUI_LLS_NOTIFICATION_PANEL_SHOWN, + hasFocus ? 0 : 1); } + // Hide statusbar and scrim if live lockscreen + // currently has focus + mBar.setStatusBarViewVisibility(!hasFocus); + mBar.getScrimController().forceHideScrims(hasFocus); + mLlsHasFocus = hasFocus; } public void onKeyguardDismissed() { if (mLiveLockScreenView != null) mLiveLockScreenView.onKeyguardDismissed(); EventLog.writeEvent(EventLogTags.SYSUI_LLS_KEYGUARD_DISMISSED, mLlsHasFocus ? 1 : 0); + // Ensure we reset visibility when keyguard is dismissed + mBar.setStatusBarViewVisibility(true); + mBar.getScrimController().forceHideScrims(false); + } + + public boolean getLiveLockScreenHasFocus() { + return mLlsHasFocus; } private Runnable mAddNewLiveLockScreenRunnable = new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index a8e977fae0a78..f7d6f852b7c2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -279,13 +279,15 @@ public boolean isEmergencyOnly() { } private boolean isRoaming() { - if (isCdma()) { + if (mServiceState == null) { + return false; + } else if (isCdma()) { final int iconMode = mServiceState.getCdmaEriIconMode(); return mServiceState.getCdmaEriIconIndex() != EriInfo.ROAMING_INDICATOR_OFF && (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH); } else { - return mServiceState != null && mServiceState.getRoaming(); + return mServiceState.getRoaming(); } } @@ -395,7 +397,8 @@ private final void updateTelephony() { mCurrentState.iconGroup = mDefaultIcons; } mCurrentState.dataConnected = mCurrentState.connected - && mDataState == TelephonyManager.DATA_CONNECTED; + && mDataState == TelephonyManager.DATA_CONNECTED + && mCurrentState.dataSim; mCurrentState.showSeparateRoaming = false; if (isCarrierNetworkChangeActive()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java index 1fa49568fd554..0f71bccaa8220 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java @@ -25,8 +25,9 @@ public interface Callback { void onWeatherChanged(WeatherInfo temp); } public static class WeatherInfo { - public String temp = null; + public double temp = Double.NaN; public String city = null; public String condition = null; + public int tempUnit; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java index 288bc7efd8a44..1a798f07d1422 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java @@ -16,43 +16,49 @@ package com.android.systemui.statusbar.policy; -import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Handler; -import android.provider.Settings; import android.util.Log; +import cyanogenmod.providers.CMSettings; +import cyanogenmod.providers.WeatherContract; +import cyanogenmod.weather.CMWeatherManager; +import cyanogenmod.weather.util.WeatherUtils; import java.util.ArrayList; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CITY; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CONDITION; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE_UNIT; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.CELSIUS; +import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT; + public class WeatherControllerImpl implements WeatherController { private static final String TAG = WeatherController.class.getSimpleName(); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private WeatherContentObserver mWeatherContentObserver; + private Handler mHandler; + private int mWeatherUnit; + private Uri mWeatherTempetarureUri; public static final ComponentName COMPONENT_WEATHER_FORECAST = new ComponentName( "com.cyanogenmod.lockclock", "com.cyanogenmod.lockclock.weather.ForecastActivity"); - public static final String ACTION_UPDATE_FINISHED - = "com.cyanogenmod.lockclock.action.WEATHER_UPDATE_FINISHED"; - public static final String EXTRA_UPDATE_CANCELLED = "update_cancelled"; public static final String ACTION_FORCE_WEATHER_UPDATE = "com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE"; - public static final Uri CURRENT_WEATHER_URI - = Uri.parse("content://com.cyanogenmod.lockclock.weather.provider/weather/current"); - public static final String[] WEATHER_PROJECTION = new String[]{ - "temperature", - "city", - "condition" + private static final String[] WEATHER_PROJECTION = new String[]{ + CURRENT_TEMPERATURE, + CURRENT_TEMPERATURE_UNIT, + CURRENT_CITY, + CURRENT_CONDITION }; private final ArrayList mCallbacks = new ArrayList(); - private final Receiver mReceiver = new Receiver(); private final Context mContext; private WeatherInfo mCachedInfo = new WeatherInfo(); @@ -60,10 +66,16 @@ public class WeatherControllerImpl implements WeatherController { public WeatherControllerImpl(Context context) { mContext = context; mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mHandler = new Handler(); + mWeatherContentObserver = new WeatherContentObserver(mHandler); + mWeatherTempetarureUri + = CMSettings.Global.getUriFor(CMSettings.Global.WEATHER_TEMPERATURE_UNIT); + mContext.getContentResolver().registerContentObserver( + WeatherContract.WeatherColumns.CURRENT_WEATHER_URI,true, mWeatherContentObserver); + mContext.getContentResolver().registerContentObserver(mWeatherTempetarureUri, true, + mWeatherContentObserver); + queryWeatherTempUnit(); queryWeather(); - final IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_UPDATE_FINISHED); - mContext.registerReceiver(mReceiver, filter); } public void addCallback(Callback callback) { @@ -85,17 +97,29 @@ public WeatherInfo getWeatherInfo() { } private void queryWeather() { - Cursor c = mContext.getContentResolver().query(CURRENT_WEATHER_URI, WEATHER_PROJECTION, + Cursor c = mContext.getContentResolver().query( + WeatherContract.WeatherColumns.CURRENT_WEATHER_URI, WEATHER_PROJECTION, null, null, null); if (c == null) { if(DEBUG) Log.e(TAG, "cursor was null for temperature, forcing weather update"); + //LockClock keeps track of the user settings (temp unit, search by geo location/city) + //so we delegate the responsibility of handling a weather update to LockClock mContext.sendBroadcast(new Intent(ACTION_FORCE_WEATHER_UPDATE)); } else { try { c.moveToFirst(); - mCachedInfo.temp = c.getString(0); - mCachedInfo.city = c.getString(1); - mCachedInfo.condition = c.getString(2); + double temp = c.getDouble(0); + int reportedUnit = c.getInt(1); + if (reportedUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) { + temp = WeatherUtils.celsiusToFahrenheit(temp); + } else if (reportedUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) { + temp = WeatherUtils.fahrenheitToCelsius(temp); + } + + mCachedInfo.temp = temp; + mCachedInfo.tempUnit = mWeatherUnit; + mCachedInfo.city = c.getString(2); + mCachedInfo.condition = c.getString(3); } finally { c.close(); } @@ -108,19 +132,53 @@ private void fireCallback() { } } - private final class Receiver extends BroadcastReceiver { + private class WeatherContentObserver extends ContentObserver { + + public WeatherContentObserver(Handler handler) { + super(handler); + } + @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction()); - if (intent.hasExtra(EXTRA_UPDATE_CANCELLED)) { - if (intent.getBooleanExtra(EXTRA_UPDATE_CANCELLED, false)) { - // no update - return; + public void onChange(boolean selfChange, Uri uri) { + if (uri != null) { + if (uri.compareTo(WeatherContract.WeatherColumns.CURRENT_WEATHER_URI) == 0) { + queryWeather(); + fireCallback(); + } else if (uri.compareTo(mWeatherTempetarureUri) == 0) { + queryWeatherTempUnit(); + fixCachedWeatherInfo(); + fireCallback(); + } else { + super.onChange(selfChange, uri); } } - queryWeather(); - fireCallback(); + } + + @Override + public void onChange(boolean selfChange) { + onChange(selfChange, null); } } + private void queryWeatherTempUnit() { + try { + mWeatherUnit = CMSettings.Global.getInt(mContext.getContentResolver(), + CMSettings.Global.WEATHER_TEMPERATURE_UNIT); + } catch (CMSettings.CMSettingNotFoundException e) { + //CMSettingsProvider should have taken care of setting a default value for this setting + //so how is that we ended up here?? We need to set a valid temp unit anyway to keep + //this going + mWeatherUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS; + } + } + + private void fixCachedWeatherInfo() { + if (mCachedInfo.tempUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) { + mCachedInfo.temp = WeatherUtils.celsiusToFahrenheit(mCachedInfo.temp); + mCachedInfo.tempUnit = FAHRENHEIT; + } else if (mCachedInfo.tempUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) { + mCachedInfo.temp = WeatherUtils.fahrenheitToCelsius(mCachedInfo.temp); + mCachedInfo.tempUnit = CELSIUS; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 2f04b421557e7..b6e131acec864 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -50,6 +50,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.ViewLinker; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ScrollAdapter; @@ -63,7 +64,8 @@ */ public class NotificationStackScrollLayout extends ViewGroup implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter, - ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener { + ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener, + ViewLinker.ViewLinkerParent { private static final String TAG = "NotificationStackScrollLayout"; private static final boolean DEBUG = false; @@ -234,6 +236,7 @@ public boolean onPreDraw() { private boolean mForceNoOverlappingRendering; private NotificationOverflowContainer mOverflowContainer; private final ArrayList> mTmpList = new ArrayList<>(); + private ViewLinker.ViewLinkerCallback mLinkerCallback; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -2879,6 +2882,23 @@ public boolean hasOverlappingRendering() { return !mForceNoOverlappingRendering && super.hasOverlappingRendering(); } + @Override + public void registerLinker(ViewLinker.ViewLinkerCallback callback) { + mLinkerCallback = callback; + } + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + mLinkerCallback.onAlphaChanged(alpha); + } + + @Override + public void setTranslationX(float translationX) { + super.setTranslationX(translationX); + mLinkerCallback.onTranslationXChanged(translationX); + } + /** * A listener that is notified when some child locations might have changed. */ diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index b2c90be6923f0..3e7477c0f5a4e 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -132,6 +132,12 @@ protected void reregisterAll() { public void reloadSetting(Uri uri) { String key = mListeningUris.get(uri); + + // Handle possible null keys + if (TextUtils.isEmpty(key)) { + return; + } + String value; if (uri.getAuthority().equals(CMSettings.AUTHORITY)) { value = CMSettings.Secure.getStringForUser(mContentResolver, key, mCurrentUser); diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 8ace946dd3c5b..dd47aab50813c 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -362,6 +362,8 @@ private Notification onVolumeMounted(VolumeInfo vol) { mContext.getString(R.string.ext_media_unmount_action), buildUnmountPendingIntent(vol))) .setContentIntent(browseIntent) + .setOngoing(mContext.getResources().getBoolean( + R.bool.config_persistUsbDriveNotification)) .setCategory(Notification.CATEGORY_SYSTEM) .setPriority(Notification.PRIORITY_LOW); // Non-adoptable disks can't be snoozed. diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 27c66012c8501..9fda531eaff47 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -106,7 +106,6 @@ public class VolumeDialog { private final SpTexts mSpTexts; private final SparseBooleanArray mDynamic = new SparseBooleanArray(); private final KeyguardManager mKeyguard; - private final AudioManager mAudioManager; private final int mExpandButtonAnimationDuration; private final ZenFooter mZenFooter; private final LayoutTransition mLayoutTransition; @@ -139,7 +138,6 @@ public VolumeDialog(Context context, int windowType, VolumeDialogController cont mCallback = callback; mSpTexts = new SpTexts(mContext); mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); - mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mDialog = new CustomDialog(mContext); @@ -666,8 +664,7 @@ private void updateNotificationRowH() { private void updateFooterH() { if (D.BUG) Log.d(TAG, "updateFooterH"); final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE; - final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF - && mAudioManager.isStreamAffectedByRingerMode(mActiveStream); + final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF; if (wasVisible != visible && !visible) { prepareForCollapse(); } diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 739286956aa34..25581e3743bde 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -33,7 +33,9 @@ LOCAL_PACKAGE_NAME := SystemUITests LOCAL_STATIC_JAVA_LIBRARIES := mockito-target Keyguard LOCAL_STATIC_JAVA_LIBRARIES += org.cyanogenmod.platform.internal \ android-support-v7-palette \ - android-support-v4 + android-support-v4 \ + uicommon + # sign this with platform cert, so this test is allowed to inject key events into # UI it doesn't own. This is necessary to allow screenshots to be taken diff --git a/packages/VpnDialogs/res/values-az-rAZ/strings.xml b/packages/VpnDialogs/res/values-az-rAZ/strings.xml index fdeb06f0784a7..c568e94e00f71 100644 --- a/packages/VpnDialogs/res/values-az-rAZ/strings.xml +++ b/packages/VpnDialogs/res/values-az-rAZ/strings.xml @@ -16,9 +16,8 @@ - "VPN bağlantısı yaratmaq üçün %s cəhdləri." - "Bunu həyata keçirməklə, siz tətbiqə bütün şəbəkə hərəkətinə qarışmağa icazə verirsiniz. "" Tətbiqə güvənmirsizsə qəbul etməyin. "" Əks halda, datanızın təhlükəli proqramlar tərəfindən ələ keçirilmə riskini alırsınız." - "Bu tətbiqə güvənirəm." + "Bağlantı Sorğusu" + "%s VPN bağlantı yaratmaq istəyir ki, bu da şəbəkə trafikini izləyə bilər. Yalnız mənbəyə güvəndiyiniz halda qəbul edin. VPN aktiv olan zaman <br /> <br /> <img src=vpn_icon /> ekranın yuxarısında görünür." "VPN qoşuludur" "Konfiqurasiya edin" "Əlaqəni kəs" diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml index 0f28016d952e2..ae789b2a05e4f 100644 --- a/packages/VpnDialogs/res/values-nl/strings.xml +++ b/packages/VpnDialogs/res/values-nl/strings.xml @@ -17,7 +17,7 @@ "Verbindingsverzoek" - "%s wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als u de bron vertrouwt. <br /> <br /> <img src=vpn_icon /> wordt boven aan uw scherm weergegeven wanneer VPN actief is." + "%s wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als je de bron vertrouwt. <br /> <br /> <img src=vpn_icon /> wordt boven aan je scherm weergegeven wanneer VPN actief is." "Verbinding met VPN" "Configureren" "Verbinding verbreken" diff --git a/packages/VpnDialogs/res/values-pt-rBR/strings.xml b/packages/VpnDialogs/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000000..e4154bc802a42 --- /dev/null +++ b/packages/VpnDialogs/res/values-pt-rBR/strings.xml @@ -0,0 +1,29 @@ + + + + + "Solicitação de conexão" + "%s quer configurar uma conexão VPN que permite monitorar o tráfego da rede. Aceite se confiar na origem. <br /> <br /> <img src=vpn_icon /> é exibido na parte superior da tela quando a VPN estiver ativa." + "O VPN está conectado" + "Configurar" + "Desconectar" + "Sessão:" + "Duração:" + "Enviado:" + "Recebido:" + "%1$s bytes/%2$s pacotes" + diff --git a/packages/VpnDialogs/res/values-sk/strings.xml b/packages/VpnDialogs/res/values-sk/strings.xml index 7a06554e854c7..b7ce96642719f 100644 --- a/packages/VpnDialogs/res/values-sk/strings.xml +++ b/packages/VpnDialogs/res/values-sk/strings.xml @@ -17,7 +17,7 @@ "Žiadosť o pripojenie" - "Aplikácia %s žiada o nastavenie pripojenia VPN, pomocou ktorého bude môcť sledovať návštevnosť siete. Povoľte iba v prípade, že zdroju dôverujete. <br /> <br /> <img src=vpn_icon /> – keď je sieť VPN aktívna, zobrazuje sa v hornej časti obrazovky." + "%s žiada o nastavenie pripojenia VPN, pomocou ktorého bude môcť sledovať sieťové prenosy. Povoľte iba v prípade, že zdroju dôverujete. <br /> <br /> <img src=vpn_icon /> sa zobrazuje v hornej časti obrazovky, keď je pripojenie VPN aktívne." "Sieť VPN je pripojená" "Konfigurovať" "Odpojiť" diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 14334900a1770..5875ca95b3c14 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -74,6 +74,8 @@ import java.util.Random; import java.util.TimeZone; import java.util.TreeSet; +import java.util.Timer; +import java.util.TimerTask; import static android.app.AlarmManager.RTC_WAKEUP; import static android.app.AlarmManager.RTC; @@ -127,6 +129,7 @@ class AlarmManagerService extends SystemService { private final ArrayList mTriggeredUids = new ArrayList(); private final ArrayList mBlockedUids = new ArrayList(); + private static final int BLOCKED_UID_CHECK_INTERVAL = 1000; // 1 sec. long mNativeData; private long mNextWakeup; @@ -1250,16 +1253,9 @@ public void updateBlockedUids(int uid, boolean isBlocked) { synchronized(mLock) { if(isBlocked) { mBlockedUids.add(new Integer(uid)); - if (checkReleaseWakeLock()) { - /* all the uids for which the alarms are triggered - * are either blocked or have called onSendFinished. - */ - if (mWakeLock.isHeld()) { - mWakeLock.release(); - if (localLOGV) - Slog.v(TAG, "AM WakeLock Released Internally in updateBlockedUids"); - } - } + Timer checkBlockedUidTimer = new Timer(); + checkBlockedUidTimer.schedule( new CheckBlockedUidTimerTask(uid), + BLOCKED_UID_CHECK_INTERVAL); } else { mBlockedUids.clear(); } @@ -1267,6 +1263,24 @@ public void updateBlockedUids(int uid, boolean isBlocked) { } }; + class CheckBlockedUidTimerTask extends TimerTask { + private int mUid; + CheckBlockedUidTimerTask(int uid) { + mUid = uid; + } + @Override + public void run(){ + if (mBlockedUids.contains(mUid) && mTriggeredUids.contains(mUid)) { + if (mWakeLock.isHeld()) { + mWakeLock.release(); + if (localLOGV) + Slog.v(TAG, "AM WakeLock Released Internally!!"); + return; + } + } + return; + } + } void dumpImpl(PrintWriter pw) { synchronized (mLock) { pw.println("Current Alarm Manager state:"); @@ -1745,20 +1759,6 @@ void rescheduleKernelAlarmsLocked() { } } - boolean checkReleaseWakeLock() { - if (mTriggeredUids.size() == 0 || mBlockedUids.size() == 0) - return false; - - int uid; - for (int i = 0; i < mTriggeredUids.size(); i++) { - uid = mTriggeredUids.get(i); - if (!mBlockedUids.contains(uid)) { - return false; - } - } - return true; - } - private void removeLocked(PendingIntent operation) { boolean didRemove = false; for (int i = mAlarmBatches.size() - 1; i >= 0; i--) { @@ -2277,12 +2277,6 @@ void deliverAlarmsLocked(ArrayList triggerList, long nowELAPSED) { mInFlight.add(inflight); mBroadcastRefCount++; mTriggeredUids.add(new Integer(alarm.uid)); - if (checkReleaseWakeLock()) { - if (mWakeLock.isHeld()) { - mWakeLock.release(); - if (localLOGV) Slog.v(TAG, "AM WakeLock Released Internally deliverAlarms"); - } - } if (allowWhileIdle) { // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm. @@ -2839,13 +2833,6 @@ public void onSendFinished(PendingIntent pi, Intent intent, int resultCode, mBroadcastRefCount--; mTriggeredUids.remove(new Integer(uid)); - if (checkReleaseWakeLock()) { - if (mWakeLock.isHeld()) { - mWakeLock.release(); - if (localLOGV) Slog.v(TAG, "AM WakeLock Released Internally onSendFinish"); - } - } - if (mBroadcastRefCount == 0) { if (mWakeLock.isHeld()) { mWakeLock.release(); diff --git a/services/core/java/com/android/server/AppOpsPolicy.java b/services/core/java/com/android/server/AppOpsPolicy.java index 75bca05591f50..d51983f744f96 100644 --- a/services/core/java/com/android/server/AppOpsPolicy.java +++ b/services/core/java/com/android/server/AppOpsPolicy.java @@ -60,6 +60,11 @@ public class AppOpsPolicy { public static final int CONTROL_UNKNOWN = 2; + // Rate limiting thresholds for ask operations + public static final int RATE_LIMIT_OP_COUNT = 3; + public static final int RATE_LIMIT_OPS_TOTAL_PKG_COUNT = 4; + public static final int RATE_LIMIT_OP_DELAY_CEILING = 10; + public static int stringToControl(String show) { if ("true".equalsIgnoreCase(show)) { return CONTROL_SHOW; @@ -438,4 +443,4 @@ public int getDefualtMode(int code, String packageName) { Slog.d(TAG, "Returning mode=" + mode); return mode; } -} \ No newline at end of file +} diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 83a0a99016799..3b12ed64bd8f5 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -39,8 +39,10 @@ import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.Dialog; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; @@ -51,6 +53,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -96,6 +99,7 @@ public class AppOpsService extends IAppOpsService.Stub { final Looper mLooper; final boolean mStrictEnable; AppOpsPolicy mPolicy; + private PowerManager mPowerManager; private static final int[] PRIVACY_GUARD_OP_STATES = new int[] { AppOpsManager.OP_COARSE_LOCATION, @@ -184,6 +188,7 @@ public final static class Op { final ArrayList clientTokens; public int allowedCount; public int ignoredCount; + public int delayedCount; public Op(int _uid, String _packageName, int _op, int _mode) { uid = _uid; @@ -360,8 +365,45 @@ public boolean hasExternalStorage(int uid, String packageName) { || mountMode == Zygote.MOUNT_EXTERNAL_WRITE; } }); + + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + mContext.registerReceiver(mIntentReceiver, filter); } + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_OFF)) { + synchronized (this) { + for (int i = mUidStates.size() - 1; i >= 0; i--) { + UidState uidState = mUidStates.valueAt(i); + + ArrayMap packages = uidState.pkgOps; + if (packages == null) { + continue; + } + + Iterator> it = packages.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry ent = it.next(); + Ops pkgOps = ent.getValue(); + for (int j = pkgOps.size() - 1; j >= 0; j--) { + Op curOp = pkgOps.valueAt(j); + if (DEBUG) + Log.d(TAG, "Ignoring " + curOp.packageName + " request " + + curOp.op); + curOp.dialogReqQueue.ignore(); + } + } + } + } + } + } + }; + public void packageRemoved(int uid, String packageName) { synchronized (this) { UidState uidState = mUidStates.get(uid); @@ -1058,8 +1100,50 @@ private int noteOperationUnchecked(int code, int uid, String packageName, + packageName + ")"); return switchOp.mode; } - op.noteOpCount++; - req = askOperationLocked(code, uid, packageName, switchOp); + + if (DEBUG) { + Log.d(TAG, "Package " + op.packageName + " has " + op.noteOpCount + + " requests and " + op.startOpCount + " start requests with " + + op.ignoredCount + " ignored at " + op.time + + " with a duration of " + + op.duration + " while being delayed " + op.delayedCount + + " times"); + Log.d(TAG, "Total pkops for " + ops.packageName + " " + + ops.uidState.pkgOps.size()); + } + + // First drop all request events if the device is not interactive, next + // check what the global pkg ops count for the package, + // then check op scoped count. High frequency request ops will be delayed until + // their delay count ceiling is met. This is to mitigate the overloading the + // main activity manager service handler and having watchdog kill our service. + // Google play services likes to share its uid with numerous packages to avoid + // having to grant permissions from the users perspective and thus is the worst + // example of overloading this queue -- so, to not encourage bad behavior, + // we move them to the back of the line. NOTE: these values are magic, and may need + // tuning. Ideally we'd want a ringbuffer or token bucket here to do proper rate + // limiting. + final boolean isInteractive = mPowerManager.isInteractive(); + if (isInteractive && + (ops.uidState.pkgOps.size() < AppOpsPolicy.RATE_LIMIT_OPS_TOTAL_PKG_COUNT + && op.noteOpCount < AppOpsPolicy.RATE_LIMIT_OP_COUNT + || op.delayedCount > AppOpsPolicy.RATE_LIMIT_OP_DELAY_CEILING)) { + + // Reset delayed count, most ops will never need this + if (op.delayedCount > 0) { + if (DEBUG) Log.d(TAG, "Resetting delayed count for " + op.packageName); + op.delayedCount = 0; + } + + op.noteOpCount++; + req = askOperationLocked(code, uid, packageName, switchOp); + } else { + if (isInteractive) { + op.delayedCount++; + } + op.ignoredCount++; + return AppOpsManager.MODE_IGNORED; + } } } diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index f20cfe9be15b8..839ba6e451a24 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -165,6 +165,7 @@ public final class BatteryService extends SystemService { private boolean mAdjustableNotificationLedBrightness; private int mNotificationLedBrightnessLevel = LIGHT_BRIGHTNESS_MAXIMUM; + private boolean mUseSegmentedBatteryLed = false; private boolean mMultipleNotificationLeds; private boolean mMultipleLedsEnabled = false; @@ -1048,6 +1049,11 @@ public Led(Context context, LightsManager lights) { com.android.internal.R.integer.config_notificationsBatteryLedOn); mBatteryLedOff = context.getResources().getInteger( com.android.internal.R.integer.config_notificationsBatteryLedOff); + + // Does the Device have segmented battery LED support? In this case, we send the level + // in the alpha channel of the color and let the HAL sort it out. + mUseSegmentedBatteryLed = context.getResources().getBoolean( + org.cyanogenmod.platform.internal.R.bool.config_useSegmentedBatteryLed); } private boolean isHvdcpPresent() { @@ -1089,6 +1095,9 @@ public void updateLightsLocked() { final int level = mBatteryProps.batteryLevel; final int status = mBatteryProps.batteryStatus; + mNotificationLedBrightnessLevel = mUseSegmentedBatteryLed ? level : + LIGHT_BRIGHTNESS_MAXIMUM; + if (!mLightEnabled) { // No lights if explicitly disabled mBatteryLight.turnOff(); diff --git a/services/core/java/com/android/server/net/NetPluginDelegate.java b/services/core/java/com/android/server/NetPluginDelegate.java similarity index 82% rename from services/core/java/com/android/server/net/NetPluginDelegate.java rename to services/core/java/com/android/server/NetPluginDelegate.java index 6716a6b6c29ae..18365f1e04c60 100644 --- a/services/core/java/com/android/server/net/NetPluginDelegate.java +++ b/services/core/java/com/android/server/NetPluginDelegate.java @@ -27,17 +27,16 @@ *IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.android.server.net; +package com.android.server; import dalvik.system.PathClassLoader; -import java.lang.reflect.Constructor; - import android.util.Slog; +import android.net.Network; import android.net.NetworkStats; import android.util.Log; -class NetPluginDelegate { +public class NetPluginDelegate { private static final String TAG = "ConnectivityExtension"; private static final boolean LOGV = false; @@ -47,7 +46,7 @@ class NetPluginDelegate { private static boolean extensionFailed; - static void getTetherStats(NetworkStats uidStats, NetworkStats devStats, + public static void getTetherStats(NetworkStats uidStats, NetworkStats devStats, NetworkStats xtStats) { if (!loadTetherExtJar()) { return; @@ -60,9 +59,10 @@ static void getTetherStats(NetworkStats uidStats, NetworkStats devStats, e.printStackTrace(); Log.w(TAG, "error in invoke method"); } + if (LOGV) Slog.v(TAG, "getTetherStats() X"); } - static void setQuota(String iface, long quota) { + public static void setQuota(String iface, long quota) { if (!loadTetherExtJar()) { return; } @@ -72,8 +72,20 @@ static void setQuota(String iface, long quota) { } catch (Exception ex) { Log.w(TAG, "Error calling setQuota Method on extension jar"); } + if (LOGV) Slog.v(TAG, "setQuota(" + iface + ", " + quota + ") X"); } + public static void setUpstream(Network net) { + if (LOGV) Slog.v(TAG, "setUpstream(" + net + ") E"); + loadTetherExtJar(); + try { + tetherExtensionClass.getMethod("setUpstream", Network.class).invoke( + tetherExtensionObj, net); + } catch (Exception ex) { + Log.w(TAG, "Error calling setUpstream Method on extension jar"); + } + if (LOGV) Slog.v(TAG, "setUpstream(" + net + ") E"); + } private static boolean loadTetherExtJar() { diff --git a/services/core/java/com/android/server/PermissionDialog.java b/services/core/java/com/android/server/PermissionDialog.java index 0f337b80e2667..fd676b5f8935b 100644 --- a/services/core/java/com/android/server/PermissionDialog.java +++ b/services/core/java/com/android/server/PermissionDialog.java @@ -102,6 +102,10 @@ public PermissionDialog(Context context, AppOpsService service, mHandler.obtainMessage(ACTION_IGNORED_TIMEOUT), DISMISS_TIMEOUT); } + public void ignore() { + mHandler.sendMessage(mHandler.obtainMessage(ACTION_IGNORED_TIMEOUT)); + } + private String getAppName(String packageName) { ApplicationInfo appInfo = null; PackageManager pm = mContext.getPackageManager(); diff --git a/services/core/java/com/android/server/PermissionDialogReqQueue.java b/services/core/java/com/android/server/PermissionDialogReqQueue.java index ee944271f341a..5b602e33a607b 100644 --- a/services/core/java/com/android/server/PermissionDialogReqQueue.java +++ b/services/core/java/com/android/server/PermissionDialogReqQueue.java @@ -79,4 +79,10 @@ public void notifyAll(int mode) { } } } + + public void ignore() { + if (mDialog != null) { + mDialog.ignore(); + } + } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 71ff6e942efba..5dac9539a73af 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1248,7 +1248,41 @@ public void notifyPreciseCallState(int ringingCallState, int foregroundCallState } broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState, DisconnectCause.NOT_VALID, - PreciseDisconnectCause.NOT_VALID); + PreciseDisconnectCause.NOT_VALID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + public void notifyPreciseCallStateForSubscriber(int subId, int ringingCallState, + int foregroundCallState, int backgroundCallState) { + if (!checkNotifyPermission("notifyPreciseCallStateForSubscriber()")) { + return; + } + synchronized (mRecords) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mRingingCallState = ringingCallState; + mForegroundCallState = foregroundCallState; + mBackgroundCallState = backgroundCallState; + mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState, + backgroundCallState, + DisconnectCause.NOT_VALID, + PreciseDisconnectCause.NOT_VALID); + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE) + && ((r.subId == subId) || + (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) { + try { + r.callback.onPreciseCallStateChanged(mPreciseCallState); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState, + DisconnectCause.NOT_VALID, + PreciseDisconnectCause.NOT_VALID, subId); } public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) { @@ -1270,7 +1304,8 @@ public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCaus handleRemoveListLocked(); } broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState, - mBackgroundCallState, disconnectCause, preciseDisconnectCause); + mBackgroundCallState, disconnectCause, preciseDisconnectCause, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); } public void notifyPreciseDataConnectionFailed(String reason, String apnType, @@ -1510,13 +1545,16 @@ private void broadcastDataConnectionFailed(String reason, String apnType, } private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState, - int backgroundCallState, int disconnectCause, int preciseDisconnectCause) { + int backgroundCallState, int disconnectCause, int preciseDisconnectCause, int subId) { Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED); intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState); intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState); intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState); intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause); intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause); + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); + } mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PRECISE_PHONE_STATE); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index def4c592b0a28..d79426470b425 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -264,6 +264,9 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; + +import cyanogenmod.power.PerformanceManagerInternal; + import java.util.Date; import java.text.SimpleDateFormat; @@ -1094,6 +1097,8 @@ private class Identity { */ private IVoiceInteractionSession mRunningVoice; + PerformanceManagerInternal mPerf; + /** * For some direct access we need to power manager. */ @@ -2200,6 +2205,7 @@ public void handleMessage(Message msg) { try { Intent protectedAppIntent = new Intent(); + protectedAppIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); protectedAppIntent.setComponent( new ComponentName("com.android.settings", "com.android.settings.applications.ProtectedAppsActivity")); @@ -2232,6 +2238,8 @@ public void handleMessage(Message msg) { .build(); try { int[] outId = new int[1]; + inm.cancelNotificationWithTag("android", null, + R.string.notify_package_component_protected_title, msg.arg1); inm.enqueueNotificationWithTag("android", "android", null, R.string.notify_package_component_protected_title, notification, outId, mCurrentUserId); @@ -3010,7 +3018,7 @@ final void removeLruProcessLocked(ProcessRecord app) { if (!app.killed) { Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app); Process.killProcessQuiet(app.pid); - killProcessGroup(app.info.uid, app.pid); + killProcessGroup(app.uid, app.pid); } if (lrui <= mLruProcessActivityStart) { mLruProcessActivityStart--; @@ -3385,7 +3393,7 @@ final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, // clean it up now. if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app); checkTime(startTime, "startProcess: bad proc running, killing"); - killProcessGroup(app.info.uid, app.pid); + killProcessGroup(app.uid, app.pid); handleAppDiedLocked(app, true, true); checkTime(startTime, "startProcess: done killing old proc"); } @@ -3440,6 +3448,17 @@ private final void startProcessLocked(ProcessRecord app, null /* entryPoint */, null /* entryPointArgs */); } + void launchBoost(int pid, String packageName) { + if (mPerf == null) { + mPerf = LocalServices.getService(PerformanceManagerInternal.class); + if (mPerf == null) { + Slog.e(TAG, "PerformanceManager not ready!"); + return; + } + } + mPerf.launchBoost(pid, packageName); + } + private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { long startTime = SystemClock.elapsedRealtime(); @@ -3602,6 +3621,9 @@ private final void startProcessLocked(ProcessRecord app, String hostingType, checkTime(startTime, "startProcess: building log message"); StringBuilder buf = mStringBuilder; buf.setLength(0); + if (hostingType.equals("activity")) { + launchBoost(startResult.pid, app.processName); + } buf.append("Start proc "); buf.append(startResult.pid); buf.append(':'); @@ -4921,7 +4943,7 @@ final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread, if (!fromBinderDied) { Process.killProcessQuiet(pid); } - killProcessGroup(app.info.uid, pid); + killProcessGroup(app.uid, pid); app.killed = true; } @@ -12552,6 +12574,7 @@ private void logStrictModeViolationToDropBox( synchronized (sb) { bufferWasEmpty = sb.length() == 0; appendDropBoxProcessHeaders(process, processName, sb); + sb.append("CM Version: ").append(cyanogenmod.os.Build.CYANOGENMOD_VERSION).append("\n"); sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); sb.append("System-App: ").append(isSystemApp).append("\n"); sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n"); @@ -12821,6 +12844,7 @@ public void addErrorToDropBox(String eventType, if (subject != null) { sb.append("Subject: ").append(subject).append("\n"); } + sb.append("CM Version: ").append(cyanogenmod.os.Build.CYANOGENMOD_VERSION).append("\n"); sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); if (Debug.isDebuggerConnected()) { sb.append("Debugger: Connected\n"); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index f43996616d1a7..cefa3c0a0fbd5 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1701,10 +1701,10 @@ private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); // Some activities may want to alter the system power management - if (mStackSupervisor.mPerf != null) { - mStackSupervisor.mPerf.activityResumed(next.intent); + if (mStackSupervisor.mService.mPerf != null) { + mStackSupervisor.mService.mPerf.activityResumed(next.intent); } - + // If we are currently pausing an activity, then don't do anything // until that is done. if (!mStackSupervisor.allPausedActivitiesComplete()) { @@ -1838,8 +1838,8 @@ private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options ? AppTransition.TRANSIT_ACTIVITY_CLOSE : AppTransition.TRANSIT_TASK_CLOSE, false); if (prev.task != next.task) { - if (mStackSupervisor.mPerf != null) { - mStackSupervisor.mPerf.cpuBoost(2000 * 1000); + if (mStackSupervisor.mService.mPerf != null) { + mStackSupervisor.mService.mPerf.cpuBoost(2000 * 1000); } } } @@ -1858,8 +1858,8 @@ private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options ? AppTransition.TRANSIT_TASK_OPEN_BEHIND : AppTransition.TRANSIT_TASK_OPEN, false); if (prev.task != next.task) { - if (mStackSupervisor.mPerf != null) { - mStackSupervisor.mPerf.cpuBoost(2000 * 1000); + if (mStackSupervisor.mService.mPerf != null) { + mStackSupervisor.mService.mPerf.cpuBoost(2000 * 1000); } } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index ed1a91ac4fc50..3e0206d5d52ce 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -118,8 +118,6 @@ import com.android.server.am.ActivityStack.ActivityState; import com.android.server.wm.WindowManagerService; -import cyanogenmod.power.PerformanceManagerInternal; - import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -276,8 +274,6 @@ public final class ActivityStackSupervisor implements DisplayListener { PowerManager mPm; - PerformanceManagerInternal mPerf; - /** * Is the privacy guard currently enabled? Shared between ActivityStacks */ @@ -354,17 +350,6 @@ public ActivityStackSupervisor(ActivityManagerService service, RecentTasks recen mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper()); } - private void launchBoost() { - if (mPerf == null) { - mPerf = LocalServices.getService(PerformanceManagerInternal.class); - } - if (mPerf == null) { - Slog.e(TAG, "PerformanceManager not ready!"); - } else { - mPerf.launchBoost(); - } - } - /** * At the time when the constructor runs, the power manager has not yet been * initialized. So we initialize our wakelocks afterwards. @@ -974,8 +959,13 @@ final int startActivityMayWait(IApplicationThread caller, int callingUid, try { //TODO: This needs to be a flushed out API in the future. - if (intent.getComponent() != null && AppGlobals.getPackageManager() - .isComponentProtected(callingPackage, intent.getComponent(), userId)) { + boolean isProtected = intent.getComponent() != null + && AppGlobals.getPackageManager() + .isComponentProtected(callingPackage, callingUid, + intent.getComponent(), userId) && + (intent.getFlags()&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0; + + if (isProtected) { Message msg = mService.mHandler.obtainMessage( ActivityManagerService.POST_COMPONENT_PROTECTED_MSG); //Store start flags, userid @@ -988,6 +978,7 @@ final int startActivityMayWait(IApplicationThread caller, int callingUid, } catch (RemoteException e) { e.printStackTrace(); } + final int realCallingPid = Binder.getCallingPid(); final int realCallingUid = Binder.getCallingUid(); int callingPid; @@ -1475,8 +1466,6 @@ final int startActivityLocked(IApplicationThread caller, Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) : (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : container.mActivityDisplay.mDisplayId))); - /* Acquire perf lock during new app launch */ - launchBoost(); } ActivityRecord sourceRecord = null; @@ -1893,6 +1882,29 @@ final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord so inTask = null; } + try { + //TODO: This needs to be a flushed out API in the future. + boolean isProtected = intent.getComponent() != null + && AppGlobals.getPackageManager() + .isComponentProtected(sourceRecord == null ? "android" : + sourceRecord.launchedFromPackage, r.launchedFromUid, + intent.getComponent(), r.userId) && + (intent.getFlags()&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0; + + if (isProtected && r.state == INITIALIZING) { + Message msg = mService.mHandler.obtainMessage( + ActivityManagerService.POST_COMPONENT_PROTECTED_MSG); + //Store start flags, userid + intent.setFlags(startFlags); + intent.putExtra("com.android.settings.PROTECTED_APPS_USER_ID", r.userId); + msg.obj = intent; + mService.mHandler.sendMessage(msg); + return ActivityManager.START_NOT_CURRENT_USER_ACTIVITY; + } + } catch (RemoteException e) { + e.printStackTrace(); + } + final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP; final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE; final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK; @@ -2829,7 +2841,7 @@ void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options, Str ActivityRecord top = task.stack.topRunningActivityLocked(null); /* App is launching from recent apps and it's a new process */ if(top != null && top.state == ActivityState.DESTROYED) { - launchBoost(); + mService.launchBoost(-1, top.packageName); } if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) { @@ -3114,15 +3126,15 @@ ActivityRecord findTaskLocked(ActivityRecord r) { final ActivityRecord ar = stack.findTaskLocked(r); if (ar != null) { if (ar.state == ActivityState.DESTROYED) { - launchBoost(); + mService.launchBoost(-1, r.packageName); } return ar; } } } - if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found"); - launchBoost(); + mService.launchBoost(-1, r.packageName); + if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found"); return null; } diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java index 055e33e76f670..a5d37f01622d4 100644 --- a/services/core/java/com/android/server/am/LockTaskNotify.java +++ b/services/core/java/com/android/server/am/LockTaskNotify.java @@ -51,8 +51,8 @@ public LockTaskNotify(Context context) { private boolean hasNavigationBar() { return mContext.getResources().getBoolean( com.android.internal.R.bool.config_showNavigationBar) - || CMSettings.Secure.getIntForUser(mContext.getContentResolver(), - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; + || CMSettings.Global.getIntForUser(mContext.getContentResolver(), + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; } public void showToast(int lockTaskModeState) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 33f1a1c4c2969..30f2c3ef7f650 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -578,7 +578,7 @@ void kill(String reason, boolean noisy) { } EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason); Process.killProcessQuiet(pid); - Process.killProcessGroup(info.uid, pid); + Process.killProcessGroup(uid, pid); if (!persistent) { killed = true; killedByAm = true; diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 3472db2502815..60d677208c82b 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -59,6 +59,7 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.server.IoThread; +import com.android.server.NetPluginDelegate; import com.android.server.net.BaseNetworkObserver; import java.io.FileDescriptor; @@ -1595,6 +1596,8 @@ protected void chooseUpstreamType(boolean tryCell) { sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS); } } else { + Network network = getConnectivityManager().getNetworkForType(upType); + NetPluginDelegate.setUpstream(network); LinkProperties linkProperties = getConnectivityManager().getLinkProperties(upType); if (linkProperties != null) { @@ -1629,7 +1632,6 @@ protected void chooseUpstreamType(boolean tryCell) { } } try { - Network network = getConnectivityManager().getNetworkForType(upType); if (network == null) { Log.e(TAG, "No Network for upstream type " + upType + "!"); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index ef086daa23bc3..53c36ff589fc0 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -2435,10 +2435,9 @@ private long scheduleReadyPeriodicSyncs() { final long shiftedLastPollTimeAbsolute = (0 < lastPollTimeAbsolute - mSyncRandomOffsetMillis) ? (lastPollTimeAbsolute - mSyncRandomOffsetMillis) : 0; - long remainingMillis - = periodInMillis - (shiftedNowAbsolute % periodInMillis); long timeSinceLastRunMillis = (nowAbsolute - lastPollTimeAbsolute); + long remainingMillis = periodInMillis - timeSinceLastRunMillis; // Schedule this periodic sync to run early if it's close enough to its next // runtime, and far enough from its last run time. // If we are early, there will still be time remaining in this period. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index db24b3a0a2e9d..4c847a2bcc02d 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -108,6 +108,7 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkPolicy; @@ -162,6 +163,7 @@ import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; import com.android.server.LocalServices; +import com.android.server.NetPluginDelegate; import com.google.android.collect.Lists; import org.xmlpull.v1.XmlPullParser; @@ -1208,7 +1210,11 @@ void updateNetworkRulesLocked() { final ArrayList> connIdents = new ArrayList<>(states.length); final ArraySet connIfaces = new ArraySet(states.length); for (NetworkState state : states) { - if (state.networkInfo.isConnected()) { + if (state.networkInfo.isConnected() && (state.networkCapabilities == null + || !state.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR) + || state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET))) { final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); final String baseIface = state.linkProperties.getInterfaceName(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index dce601b4f8fef..baaf055114a32 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -81,6 +81,7 @@ import android.net.INetworkStatsService; import android.net.INetworkStatsSession; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; @@ -123,6 +124,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.LocalServices; +import com.android.server.NetPluginDelegate; import com.android.server.connectivity.Tethering; import java.io.File; @@ -940,7 +942,11 @@ private void updateIfacesLocked() { final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { - if (state.networkInfo.isConnected()) { + if (state.networkInfo.isConnected() && (state.networkCapabilities == null + || !state.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR) + || state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET))) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 36818b5ad6973..1540cd85f1a54 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -339,6 +339,8 @@ public class NotificationManagerService extends SystemService { private boolean mDisableDuckingWhileMedia; private boolean mActiveMedia; + private boolean mMultiColorNotificationLed; + private static final int MY_UID = Process.myUid(); private static final int MY_PID = Process.myPid(); private static final int REASON_DELEGATE_CLICK = 1; @@ -1200,6 +1202,9 @@ void onPolicyChanged() { mDefaultNotificationLedOff = resources.getInteger( R.integer.config_defaultNotificationLedOff); + mMultiColorNotificationLed = resources.getBoolean( + R.bool.config_multiColorNotificationLed); + mNotificationPulseCustomLedValues = new HashMap(); mPackageNameMappings = new HashMap(); @@ -1553,6 +1558,20 @@ public int getPackageVisibilityOverride(String pkg, int uid) { return mRankingHelper.getPackageVisibilityOverride(pkg, uid); } + @Override + public void setShowNotificationForPackageOnKeyguard( + String pkg, int uid, int status) { + checkCallerIsSystem(); + mRankingHelper.setShowNotificationForPackageOnKeyguard(pkg, uid, status); + savePolicyFile(); + } + + @Override + public int getShowNotificationForPackageOnKeyguard(String pkg, int uid) { + enforceSystemOrSystemUI("INotificationManager.getShowNotificationForPackageOnKeyguard"); + return mRankingHelper.getShowNotificationForPackageOnKeyguard(pkg, uid); + } + /** * System-only API for getting a list of current (i.e. not cleared) notifications. * @@ -3518,6 +3537,9 @@ private int generateLedColorForNotification(NotificationRecord ledNotification) if (!mAutoGenerateNotificationColor) { return mDefaultNotificationColor; } + if (!mMultiColorNotificationLed) { + return mDefaultNotificationColor; + } final String packageName = ledNotification.sbn.getPackageName(); final String mapping = mapPackage(packageName); int color = mDefaultNotificationColor; diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index 803db10cd03f6..320cf758600e3 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -27,4 +27,9 @@ public interface RankingConfig { int getPackageVisibilityOverride(String packageName, int uid); void setPackageVisibilityOverride(String packageName, int uid, int visibility); + + void setShowNotificationForPackageOnKeyguard(String packageName, int uid, int status); + + int getShowNotificationForPackageOnKeyguard(String packageName, int uid); + } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 2e986a9312796..51123708bb84c 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -51,6 +51,7 @@ public class RankingHelper implements RankingConfig { private static final String ATT_PRIORITY = "priority"; private static final String ATT_PEEKABLE = "peekable"; private static final String ATT_VISIBILITY = "visibility"; + private static final String ATT_KEYGUARD = "keyguard"; private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT; private static final boolean DEFAULT_PEEKABLE = true; @@ -143,6 +144,8 @@ public void readXml(XmlPullParser parser, boolean forRestore) int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY); boolean peekable = safeBool(parser, ATT_PEEKABLE, DEFAULT_PEEKABLE); int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY); + int keyguard = safeInt(parser, ATT_KEYGUARD, + Notification.SHOW_ALL_NOTI_ON_KEYGUARD); String name = parser.getAttributeValue(null, ATT_NAME); if (!TextUtils.isEmpty(name)) { @@ -172,6 +175,9 @@ public void readXml(XmlPullParser parser, boolean forRestore) if (vis != DEFAULT_VISIBILITY) { r.visibility = vis; } + if (keyguard != Notification.SHOW_ALL_NOTI_ON_KEYGUARD) { + r.keyguard = keyguard; + } } } } @@ -200,7 +206,8 @@ private void removeDefaultRecords() { for (int i = N - 1; i >= 0; i--) { final Record r = mRecords.valueAt(i); if (r.priority == DEFAULT_PRIORITY && r.peekable == DEFAULT_PEEKABLE - && r.visibility == DEFAULT_VISIBILITY) { + && r.visibility == DEFAULT_VISIBILITY + && r.keyguard == Notification.SHOW_ALL_NOTI_ON_KEYGUARD) { mRecords.removeAt(i); } } @@ -227,6 +234,9 @@ public void writeXml(XmlSerializer out, boolean forBackup) throws IOException { if (r.visibility != DEFAULT_VISIBILITY) { out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); } + if (r.keyguard != Notification.SHOW_ALL_NOTI_ON_KEYGUARD) { + out.attribute(null, ATT_KEYGUARD, Integer.toBinaryString(r.keyguard)); + } if (!forBackup) { out.attribute(null, ATT_UID, Integer.toString(r.uid)); } @@ -377,6 +387,23 @@ public void setPackageVisibilityOverride(String packageName, int uid, int visibi updateConfig(); } + @Override + public int getShowNotificationForPackageOnKeyguard(String packageName, int uid) { + final Record r = mRecords.get(recordKey(packageName, uid)); + return r != null ? r.keyguard : Notification.SHOW_ALL_NOTI_ON_KEYGUARD; + } + + @Override + public void setShowNotificationForPackageOnKeyguard( + String packageName, int uid, int keyguard) { + if (keyguard == getShowNotificationForPackageOnKeyguard(packageName, uid)) { + return; + } + getOrCreateRecord(packageName, uid).keyguard = keyguard; + removeDefaultRecords(); + updateConfig(); + } + public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) { if (filter == null) { final int N = mSignalExtractors.length; @@ -459,6 +486,7 @@ private static class Record { int priority = DEFAULT_PRIORITY; boolean peekable = DEFAULT_PEEKABLE; int visibility = DEFAULT_VISIBILITY; + int keyguard = Notification.SHOW_ALL_NOTI_ON_KEYGUARD; } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index eb9a192a2c790..459703118481f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5854,12 +5854,15 @@ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime } synchronized (mPackages) { if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, - "Marking prebundled packages for user " + prebundledUserId); + "Marking prebundled package " + pkg.packageName + + " for user " + prebundledUserId); mSettings.markPrebundledPackageInstalledLPr(prebundledUserId, pkg.packageName); // do this for every other user for (UserInfo userInfo : sUserManager.getUsers(true)) { if (userInfo.id == prebundledUserId) continue; + if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, + "Marking for secondary user " + userInfo.id); mSettings.markPrebundledPackageInstalledLPr(userInfo.id, pkg.packageName); } @@ -5991,15 +5994,17 @@ private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int s if ((parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0) { synchronized (mPackages) { PackageSetting existingSettings = mSettings.peekPackageLPr(pkg.packageName); - if (mSettings.wasPrebundledPackageInstalledLPr(user.getIdentifier() - , pkg.packageName) && existingSettings == null) { - // The prebundled app was installed at some point in time, but now it is - // gone. Assume that the user uninstalled it intentionally: do not reinstall. + + if (!mSettings.shouldPrebundledPackageBeInstalledForUserLPr(existingSettings, + user.getIdentifier(), pkg.packageName)) { + // The prebundled app was installed at some point for the owner and isn't + // currently installed for the owner, dont install it for a new user + // OR the prebundled app was installed for the user at some point and isn't + // current installed for the user, so skip reinstalling it throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE, "skip reinstall for " + pkg.packageName); - } else if (existingSettings == null && - !mSettings.shouldPrebundledPackageBeInstalled(mContext.getResources(), - pkg.packageName, mCustomResources)) { + } else if (!mSettings.shouldPrebundledPackageBeInstalledForRegion( + mContext.getResources(), pkg.packageName, mCustomResources)) { // The prebundled app is not needed for the default mobile country code, // skip installing it throw new PackageManagerException(INSTALL_FAILED_REGION_LOCKED_PREBUNDLE, @@ -8319,6 +8324,8 @@ private void compileResourcesWithAapt(String target, PackageParser.Package pkg) int pkgId; if ("android".equals(target)) { pkgId = Resources.THEME_FRAMEWORK_PKG_ID; + } else if ("cyanogenmod.platform".equals(target)) { + pkgId = Resources.THEME_CM_PKG_ID; } else if (isCommonResources) { pkgId = Resources.THEME_COMMON_PKG_ID; } else { @@ -17260,10 +17267,12 @@ public void setComponentProtectedSetting(ComponentName componentName, boolean ne } @Override - public boolean isComponentProtected(String callingPackage, + public boolean isComponentProtected(String callingPackage, int callingUid, ComponentName componentName, int userId) { if (DEBUG_PROTECTED) Log.d(TAG, "Checking if component is protected " - + componentName.flattenToShortString() + " from calling package " + callingPackage); + + componentName.flattenToShortString() + " from calling package " + callingPackage + + " and callinguid " + callingUid); + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "set protected"); //Allow managers full access @@ -17284,8 +17293,23 @@ public boolean isComponentProtected(String callingPackage, return false; } + //If this component is launched from a validation component, allow it. if (TextUtils.equals(PROTECTED_APPS_TARGET_VALIDATION_COMPONENT, - componentName.flattenToString())) { + componentName.flattenToString()) && callingUid == Process.SYSTEM_UID) { + return false; + } + + //If this component is launched from the system or a uid of a protected component, allow it. + boolean fromProtectedComponentUid = false; + for (String protectedComponentManager : protectedComponentManagers) { + if (callingUid == getPackageUid(protectedComponentManager, userId)) { + fromProtectedComponentUid = true; + } + } + + if (TextUtils.equals(callingPackage, "android") && callingUid == Process.SYSTEM_UID + || callingPackage == null && fromProtectedComponentUid) { + if (DEBUG_PROTECTED) Log.d(TAG, "Calling package is android or manager, allow"); return false; } @@ -17295,14 +17319,8 @@ public boolean isComponentProtected(String callingPackage, synchronized (mPackages) { pkgSetting = mSettings.mPackages.get(packageName); - if (pkgSetting == null) { - if (className == null) { - throw new IllegalArgumentException( - "Unknown package: " + packageName); - } - throw new IllegalArgumentException( - "Unknown component: " + packageName - + "/" + className); + if (pkgSetting == null || className == null) { + return false; } // Get all the protected components components = pkgSetting.getProtectedComponents(userId); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 502afa0721282..38478c2e6e270 100755 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2524,7 +2524,7 @@ boolean wasPrebundledPackageInstalledLPr(int userId, String packageName) { return mPrebundledPackages.get(userId).contains(packageName); } - boolean shouldPrebundledPackageBeInstalled(Resources res, String packageName, + boolean shouldPrebundledPackageBeInstalledForRegion(Resources res, String packageName, Resources configuredResources) { // Default fallback on lack of bad package if (TextUtils.isEmpty(packageName)) { @@ -2557,6 +2557,37 @@ boolean shouldPrebundledPackageBeInstalled(Resources res, String packageName, return !ArrayUtils.contains(prebundledArray, packageName); } + boolean shouldPrebundledPackageBeInstalledForUserLPr(PackageSetting existingSettings, + int userIdentifier, String packageName) { + + // Check if package installed for the user + final boolean isInstalledForUser = (existingSettings != null + && existingSettings.getInstalled(userIdentifier)); + + // Check if package installed for the owner + final boolean isInstalledForOwner = (existingSettings != null + && existingSettings.getInstalled(UserHandle.USER_OWNER)); + + // Check if the user is the owner + final boolean isOwner = userIdentifier == UserHandle.USER_OWNER; + + // If the given user is not the owner, and the prebundle was installed for the owner + // but is no longer installed, and isn't currently installed for the user, + // skip installing it. + if (!isOwner && wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, packageName) + && !isInstalledForOwner && !isInstalledForUser) { + return false; + } + + // If the given package was installed for the user and isn't currently, skip reinstalling it + if (wasPrebundledPackageInstalledLPr(userIdentifier, packageName) && + !isInstalledForUser) { + return false; + } + + return true; + } + void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg) throws java.io.IOException { serializer.startTag(null, "updated-package"); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 06c3682fa988a..fd9979f1c552a 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -262,6 +262,17 @@ void systemReady() { Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); } } + UserInfo currentGuestUser = null; + synchronized (mPackagesLock) { + currentGuestUser = findCurrentGuestUserLocked(); + } + if (currentGuestUser != null && !hasUserRestriction( + UserManager.DISALLOW_CONFIG_WIFI, currentGuestUser.id)) { + // If a guest user currently exists, apply the DISALLOW_CONFIG_WIFI option + // to it, in case this guest was created in a previous version where this + // user restriction was not a default guest restriction. + setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id); + } } @Override @@ -509,6 +520,7 @@ private void initDefaultGuestRestrictions() { if (mGuestRestrictions.isEmpty()) { mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true); mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true); + mGuestRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, true); } } diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java index 4e21580fdd50e..34fc9057dcb97 100644 --- a/services/core/java/com/android/server/policy/GlobalActions.java +++ b/services/core/java/com/android/server/policy/GlobalActions.java @@ -293,7 +293,7 @@ private void handleShow() { private Context getUiContext() { if (mUiContext == null) { mUiContext = ThemeUtils.createUiContext(mContext); - mUiContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); + mUiContext.setTheme(com.android.internal.R.style.Theme_Power_Dialog); } return mUiContext != null ? mUiContext : mContext; } @@ -417,7 +417,8 @@ public boolean showBeforeProvisioning() { params.mOnClickListener = this; params.mForceInverseBackground = true; - GlobalActionsDialog dialog = new GlobalActionsDialog(getUiContext(), params); + GlobalActionsDialog dialog = new GlobalActionsDialog(/** system context **/ mContext, + /** themed context **/ getUiContext(), params); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.getListView().setItemsCanFocus(true); @@ -1457,6 +1458,7 @@ private static Bitmap createCircularClip(Bitmap input, int width, int height) { private static final class GlobalActionsDialog extends Dialog implements DialogInterface { private final Context mContext; + private Context mSystemContext = null; private final int mWindowTouchSlop; private final AlertController mAlert; private final MyAdapter mAdapter; @@ -1466,7 +1468,7 @@ private static final class GlobalActionsDialog extends Dialog implements DialogI private boolean mIntercepted; private boolean mCancelOnUp; - public GlobalActionsDialog(Context context, AlertParams params) { + private GlobalActionsDialog(Context context, AlertParams params) { super(context, getDialogTheme(context)); mContext = getContext(); mAlert = new AlertController(mContext, this, getWindow()); @@ -1475,6 +1477,19 @@ public GlobalActionsDialog(Context context, AlertParams params) { params.apply(mAlert); } + /** + * Utilized for a working global actions dialog for both accessibility services (which + * require a system context) and + * @param systemContext Base context (should be from system process) + * @param themedContext Themed context (created from system ui) + * @param params + */ + public GlobalActionsDialog(Context systemContext, Context themedContext, + AlertParams params) { + this(themedContext, params); + mSystemContext = systemContext; + } + private static int getDialogTheme(Context context) { TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme, @@ -1488,8 +1503,8 @@ protected void onStart() { // of dismissing the dialog on touch outside. This is because the dialog // is dismissed on the first down while the global gesture is a long press // with two fingers anywhere on the screen. - if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) { - mEnableAccessibilityController = new EnableAccessibilityController(mContext, + if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mSystemContext)) { + mEnableAccessibilityController = new EnableAccessibilityController(mSystemContext, new Runnable() { @Override public void run() { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index cb150dcc19d9a..33ede769d0d15 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -898,8 +898,8 @@ void observe() { resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION_ANGLES), false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(CMSettings.Secure.getUriFor( - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), false, this, + resolver.registerContentObserver(CMSettings.Global.getUriFor( + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR), false, this, UserHandle.USER_ALL); resolver.registerContentObserver(CMSettings.System.getUriFor( CMSettings.System.VOLBTN_MUSIC_CONTROLS), false, this, @@ -1764,10 +1764,15 @@ public void onSwipeFromLeft() { mNavigationBarLeftInLandscape) { requestTransientBars(mNavigationBar); } - if (mShowKeyguardOnLeftSwipe && isKeyguardShowingOrOccluded()) { + boolean focusedWindowIsExternalKeyguard = false; + if (mFocusedWindow != null) { + focusedWindowIsExternalKeyguard = (mFocusedWindow.getAttrs().type + & WindowManager.LayoutParams.TYPE_KEYGUARD_PANEL) != 0; + } + if (mShowKeyguardOnLeftSwipe && isKeyguardShowingOrOccluded() + && focusedWindowIsExternalKeyguard) { // Show keyguard mKeyguardDelegate.showKeyguard(); - mShowKeyguardOnLeftSwipe = false; } } @Override @@ -2133,8 +2138,8 @@ public void updateSettings() { updateWakeGestureListenerLp(); } - boolean devForceNavbar = CMSettings.Secure.getIntForUser(resolver, - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; + boolean devForceNavbar = CMSettings.Global.getIntForUser(resolver, + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; if (devForceNavbar != mDevForceNavbar) { mDevForceNavbar = devForceNavbar; if (mCMHardware.isSupported(CMHardwareManager.FEATURE_KEY_DISABLE)) { @@ -3152,6 +3157,12 @@ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int p // timeout. if (keyCode == KeyEvent.KEYCODE_HOME) { + if (mTopFullscreenOpaqueWindowState != null && + (mTopFullscreenOpaqueWindowState.getAttrs().privateFlags + & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS) != 0 + && mScreenOnFully) { + return 0; + } // If we have released the home key, and didn't do anything else // while it was pressed, then it is time to go home! if (!down) { @@ -3252,6 +3263,13 @@ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int p return 0; } + if (mTopFullscreenOpaqueWindowState != null && + (mTopFullscreenOpaqueWindowState.getAttrs().privateFlags + & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS) != 0 + && mScreenOnFully) { + return 0; + } + if (down) { if (mPressOnMenuBehavior == KEY_ACTION_APP_SWITCH || mLongPressOnMenuBehavior == KEY_ACTION_APP_SWITCH) { @@ -3317,6 +3335,13 @@ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int p } return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { + if (mTopFullscreenOpaqueWindowState != null && + (mTopFullscreenOpaqueWindowState.getAttrs().privateFlags + & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS) != 0 + && mScreenOnFully) { + return 0; + } + if (!keyguardOn) { if (down) { if (mPressOnAppSwitchBehavior == KEY_ACTION_APP_SWITCH @@ -5829,7 +5854,8 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { case KeyEvent.KEYCODE_POWER: { if (mTopFullscreenOpaqueWindowState != null && (mTopFullscreenOpaqueWindowState.getAttrs().privateFlags - & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0 + & (WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS | + WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY)) != 0 && mScreenOnFully) { return result; } @@ -5941,7 +5967,8 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { } if (isWakeKey) { - wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY", true); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY", + event.getKeyCode() == KeyEvent.KEYCODE_WAKEUP /* check prox only on wake key*/); } return result; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 21fa44d92145b..a197c6ecf12b6 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -112,6 +112,8 @@ public final class PowerManagerService extends SystemService private static final int MSG_SANDMAN = 2; // Message: Sent when the screen brightness boost expires. private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3; + // Message: Sent when the sandman fails to acknowledge the dream state change. + private static final int MSG_SANDMAN_TIMEOUT = 4; private static final int MSG_WAKE_UP = 5; @@ -139,6 +141,8 @@ public final class PowerManagerService extends SystemService private static final int DIRTY_DOCK_STATE = 1 << 10; // Dirty bit: brightness boost changed private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11; + // Dirty bit: sandman state changed + private static final int DIRTY_SANDMAN_STATE = 1 << 12; // Summarizes the state of all active wakelocks. private static final int WAKE_LOCK_CPU = 1 << 0; @@ -183,6 +187,9 @@ public final class PowerManagerService extends SystemService // Max time (microseconds) to allow a CPU boost for private static final int MAX_CPU_BOOST_TIME = 5000000; + // Max time (milliseconds) to wait for the sandman to acknowledge dream state changes + private static final int SANDMAN_RESPONSE_TIMEOUT = 2 * 1000; + private final Context mContext; private final ServiceThread mHandlerThread; private final PowerManagerHandler mHandler; @@ -282,6 +289,13 @@ public final class PowerManagerService extends SystemService // True if the display suspend blocker has been acquired. private boolean mHoldingDisplaySuspendBlocker; + // The suspend blocker used to keep the CPU alive when dreams are requesting to be + // started. + private final SuspendBlocker mDreamSuspendBlocker; + + // True if the dream suspend blocker has been acquired. + private boolean mHoldingDreamSuspendBlocker; + // True if systemReady() has been called. private boolean mSystemReady; @@ -543,6 +557,7 @@ public PowerManagerService(Context context) { synchronized (mLock) { mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); + mDreamSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Dreams"); mDisplaySuspendBlocker.acquire(); mHoldingDisplaySuspendBlocker = true; mHalAutoSuspendModeEnabled = false; @@ -703,8 +718,8 @@ mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"), resolver.registerContentObserver(CMSettings.Global.getUriFor( CMSettings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED), false, mSettingsObserver, UserHandle.USER_ALL); - resolver.registerContentObserver(CMSettings.Secure.getUriFor( - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR), + resolver.registerContentObserver(CMSettings.Global.getUriFor( + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR), false, mSettingsObserver, UserHandle.USER_ALL); // Go. @@ -850,8 +865,8 @@ private void updateSettingsLocked() { mKeyboardBrightness = CMSettings.Secure.getIntForUser(resolver, CMSettings.Secure.KEYBOARD_BRIGHTNESS, mKeyboardBrightnessSettingDefault, UserHandle.USER_CURRENT); - mForceNavbar = CMSettings.Secure.getIntForUser(resolver, - CMSettings.Secure.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; + mForceNavbar = CMSettings.Global.getIntForUser(resolver, + CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1; mDirty |= DIRTY_SETTINGS; } @@ -1927,15 +1942,16 @@ private void updateDreamLocked(int dirty, boolean displayBecameReady) { | DIRTY_PROXIMITY_POSITIVE | DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) { if (mDisplayReady) { - scheduleSandmanLocked(); + scheduleSandmanLocked(false); } } } - private void scheduleSandmanLocked() { + private void scheduleSandmanLocked(boolean fromDreamService) { if (!mSandmanScheduled) { mSandmanScheduled = true; Message msg = mHandler.obtainMessage(MSG_SANDMAN); + msg.arg1 = fromDreamService ? 1 : 0; msg.setAsynchronous(true); mHandler.sendMessage(msg); } @@ -1948,7 +1964,7 @@ private void scheduleSandmanLocked() { * the dream and we don't want to hold our lock while doing so. There is a risk that * the device will wake or go to sleep in the meantime so we have to handle that case. */ - private void handleSandman() { // runs on handler thread + private void handleSandman(boolean fromDreamService) { // runs on handler thread // Handle preconditions. final boolean startDreaming; final int wakefulness; @@ -1961,6 +1977,30 @@ private void handleSandman() { // runs on handler thread } else { startDreaming = false; } + // We hold the display suspend blocker as long as mSandmanSummoned is true + // That guarantees this code to be run before the system enters suspend. However, + // once we exit this lock, we are no longer guaranteed to stay awake. Hold a wake + // lock that is released once the dream service has acknowledged the request + // to start. + if (mDreamManager != null) { + if (startDreaming) { + if (!mHoldingDreamSuspendBlocker) { + mDreamSuspendBlocker.acquire(); + mHoldingDreamSuspendBlocker = true; + Message msg = mHandler.obtainMessage(MSG_SANDMAN_TIMEOUT); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, SANDMAN_RESPONSE_TIMEOUT); + mDirty |= DIRTY_SANDMAN_STATE; + updatePowerStateLocked(); + } + } else if (fromDreamService) { + mHandler.removeMessages(MSG_SANDMAN_TIMEOUT); + if (mHoldingDreamSuspendBlocker) { + mDreamSuspendBlocker.release(); + mHoldingDreamSuspendBlocker = false; + } + } + } } // Start dreaming if needed. @@ -2390,6 +2430,11 @@ private boolean needDisplaySuspendBlockerLocked() { if (mScreenBrightnessBoostInProgress) { return true; } + + if (mSandmanSummoned) { + return true; + } + // Let the system suspend if the screen is off or dozing. return false; } @@ -2985,7 +3030,7 @@ private final class DreamReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { synchronized (mLock) { - scheduleSandmanLocked(); + scheduleSandmanLocked(true); } } } @@ -3042,7 +3087,8 @@ public void handleMessage(Message msg) { handleUserActivityTimeout(); break; case MSG_SANDMAN: - handleSandman(); + boolean fromDreamService = msg.arg1 == 1; + handleSandman(fromDreamService); break; case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT: handleScreenBrightnessBoostTimeout(); @@ -3051,6 +3097,10 @@ public void handleMessage(Message msg) { cleanupProximity(); ((Runnable) msg.obj).run(); break; + case MSG_SANDMAN_TIMEOUT: + Slog.w(TAG, "Sandman unresponsive, releasing suspend blocker"); + handleSandman(true); + break; } } } @@ -3868,10 +3918,10 @@ public void updateBlockedUids(int uid, boolean isBlocked) { else { mBlockedUids.clear(); } - } - if(changed){ - mDirty |= DIRTY_WAKE_LOCKS; - updatePowerStateLocked(); + if(changed){ + mDirty |= DIRTY_WAKE_LOCKS; + updatePowerStateLocked(); + } } } } diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java index 34b6e2b645fd6..36a9ca26d9c70 100644 --- a/services/core/java/com/android/server/power/ShutdownThread.java +++ b/services/core/java/com/android/server/power/ShutdownThread.java @@ -630,6 +630,16 @@ public void onShutDownComplete(int statusCode) throws RemoteException { } }; + final String cryptoStatus = SystemProperties.get("ro.crypto.state", "unsupported"); + final boolean isEncrypted = "encrypted".equalsIgnoreCase(cryptoStatus); + + if (mRebootUpdate && isEncrypted) { + sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null); + + // If it's to reboot to install update, invoke uncrypt via init service. + uncrypt(); + } + Log.i(TAG, "Shutting down MountService"); // Set initial variables and time out time. @@ -665,12 +675,6 @@ public void onShutDownComplete(int statusCode) throws RemoteException { } } } - if (mRebootUpdate) { - sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null); - - // If it's to reboot to install update, invoke uncrypt via init service. - uncrypt(); - } rebootOrShutdown(mContext, mReboot, mRebootReason); } @@ -1002,7 +1006,7 @@ private static Context getUiContext(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION)) { uiContext.setTheme(com.android.internal.R.style.Theme_Leanback_Dialog_Alert); } else { - uiContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); + uiContext.setTheme(com.android.internal.R.style.Theme_Power_Dialog); } } return uiContext != null ? uiContext : context; diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index e9ace29395a26..0e519533118ba 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -249,7 +249,7 @@ public void disableForUser(int what, IBinder token, String pkg, int userId) { */ @Override public void disable2(int what, IBinder token, String pkg) { - disableForUser(what, token, pkg, mCurrentUserId); + disable2ForUser(what, token, pkg, mCurrentUserId); } /** diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 5de1837fbabe4..3289c2ea9b0cb 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -30,6 +30,8 @@ import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING; import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; import android.os.RemoteException; import android.util.Slog; import android.util.SparseArray; @@ -44,6 +46,8 @@ import com.android.server.wm.WindowManagerService.LayoutFields; +import cyanogenmod.providers.CMSettings; + import java.io.PrintWriter; import java.util.ArrayList; @@ -98,7 +102,7 @@ public class WindowAnimator { /** Use one animation for all entering activities after keyguard is dismissed. */ Animation mPostKeyguardExitAnimation; - private final boolean mBlurUiEnabled; + private boolean mKeyguardBlurEnabled; // forceHiding states. static final int KEYGUARD_NOT_SHOWN = 0; @@ -120,9 +124,14 @@ private String forceHidingToString() { mContext = service.mContext; mPolicy = service.mPolicy; - mBlurUiEnabled = mContext.getResources().getBoolean( + boolean blurUiEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_ui_blur_enabled); + if (blurUiEnabled) { + SettingsObserver observer = new SettingsObserver(new Handler()); + observer.observe(mContext); + } + mAnimationFrameCallback = new Choreographer.FrameCallback() { public void doFrame(long frameTimeNs) { synchronized (mService.mWindowMap) { @@ -211,7 +220,9 @@ private boolean shouldForceHide(WindowState win) { // Show SHOW_WHEN_LOCKED windows that turn on the screen allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen; // Show windows that use TYPE_STATUS_BAR_SUB_PANEL when locked - allowWhenLocked |= win.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD_PANEL; + allowWhenLocked |= win.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD_PANEL && + winShowWhenLocked == null; + if (appShowWhenLocked != null) { allowWhenLocked |= appShowWhenLocked == win.mAppToken @@ -223,7 +234,7 @@ private boolean shouldForceHide(WindowState win) { // Only hide windows if the keyguard is active and not animating away. boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded() - && (mForceHiding != KEYGUARD_ANIMATING_OUT && !mBlurUiEnabled); + && (mForceHiding != KEYGUARD_ANIMATING_OUT && !mKeyguardBlurEnabled); return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY); } @@ -232,7 +243,7 @@ private void updateWindowsLocked(final int displayId) { final WindowList windows = mService.getWindowListLocked(displayId); - if (mKeyguardGoingAway && !mBlurUiEnabled) { + if (mKeyguardGoingAway && !mKeyguardBlurEnabled) { for (int i = windows.size() - 1; i >= 0; i--) { WindowState win = windows.get(i); if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) { @@ -247,7 +258,7 @@ private void updateWindowsLocked(final int displayId) { // Create a new animation to delay until keyguard is gone on its own. winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f); winAnimator.mAnimation.setDuration( - mBlurUiEnabled ? 0 : KEYGUARD_ANIM_TIMEOUT_MS); + mKeyguardBlurEnabled ? 0 : KEYGUARD_ANIM_TIMEOUT_MS); winAnimator.mAnimationIsEntrance = false; winAnimator.mAnimationStartTime = -1; winAnimator.mKeyguardGoingAwayAnimation = true; @@ -337,7 +348,7 @@ private void updateWindowsLocked(final int displayId) { if (nowAnimating && win.mWinAnimator.mKeyguardGoingAwayAnimation) { mForceHiding = KEYGUARD_ANIMATING_OUT; } else { - mForceHiding = win.isDrawnLw() && !mBlurUiEnabled ? + mForceHiding = win.isDrawnLw() && !mKeyguardBlurEnabled ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN; } } @@ -890,4 +901,30 @@ ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) { private class DisplayContentsAnimator { ScreenRotationAnimation mScreenRotationAnimation = null; } + + private class SettingsObserver extends ContentObserver { + public SettingsObserver(Handler handler) { + super(handler); + } + + public void observe(Context context) { + context.getContentResolver().registerContentObserver( + CMSettings.Secure.getUriFor(CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED), + false, + this); + + onChange(true); + } + + public void unobserve(Context context) { + context.getContentResolver().unregisterContentObserver(this); + } + + @Override + public void onChange(boolean selfChange) { + // default to being enabled since we are here because the blur config was set to true + mKeyguardBlurEnabled = CMSettings.Secure.getInt(mContext.getContentResolver(), + CMSettings.Secure.LOCK_SCREEN_BLUR_ENABLED, 1) == 1; + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b67f488f5f67e..6f44911ef6182 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10166,6 +10166,7 @@ private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMe } } + winAnimator.computeShownFrameLocked(); winAnimator.setSurfaceBoundariesLocked(recoveringMemory); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 51696078c2a83..d69fe11b07e74 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -99,6 +99,9 @@ import dalvik.system.VMRuntime; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; @@ -326,7 +329,7 @@ private void performPendingShutdown() { private void createSystemContext() { ActivityThread activityThread = ActivityThread.systemMain(); mSystemContext = activityThread.getSystemContext(); - mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar); + mSystemContext.setTheme(com.android.internal.R.style.Theme_Power_Dialog); } /** @@ -455,8 +458,8 @@ private void startOtherServices() { boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false); boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false); boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1"); - String[] externalServices = context.getResources().getStringArray( - org.cyanogenmod.platform.internal.R.array.config_externalCMServices); + String externalServer = context.getResources().getString( + org.cyanogenmod.platform.internal.R.string.config_externalSystemServer); try { Slog.i(TAG, "Reading configuration..."); @@ -1052,13 +1055,22 @@ private void startOtherServices() { // MMS service broker mmsService = mSystemServiceManager.startService(MmsServiceBroker.class); - for (String service : externalServices) { - try { - Slog.i(TAG, service); - mSystemServiceManager.startService(service); - } catch (Throwable e) { - reportWtf("starting " + service , e); - } + final Class serverClazz; + try { + serverClazz = Class.forName(externalServer); + final Constructor constructor = serverClazz.getDeclaredConstructor(Context.class); + constructor.setAccessible(true); + final Object baseObject = constructor.newInstance(mSystemContext); + final Method method = baseObject.getClass().getDeclaredMethod("run"); + method.setAccessible(true); + method.invoke(baseObject); + } catch (ClassNotFoundException + | IllegalAccessException + | InvocationTargetException + | InstantiationException + | NoSuchMethodException e) { + Slog.wtf(TAG, "Unable to start " + externalServer); + Slog.wtf(TAG, e); } // It is now time to start up the app processes... @@ -1177,15 +1189,6 @@ public void run() { Slog.i(TAG, "WebViewFactory preparation"); WebViewFactory.prepareWebViewInSystemServer(); - // Start Nfc before SystemUi to ensure NfcTile and other apps gets a - // valid NfcAdapter from NfcManager - try { - startNfcService(context); - } catch (Throwable e) { - // Don't crash. Nfc is an optional service. Just annotate that isn't ready - Slog.e(TAG, "Nfc service didn't start. Nfc will not be available.", e); - } - try { startSystemUi(context); } catch (Throwable e) { @@ -1304,23 +1307,4 @@ static final void startSystemUi(Context context) { //Slog.d(TAG, "Starting service: " + intent); context.startServiceAsUser(intent, UserHandle.OWNER); } - - static final void startNfcService(Context context) { - IPackageManager pm = ActivityThread.getPackageManager(); - if (pm == null) { - Slog.w(TAG, "Cannot get package manager, assuming no NFC feature"); - return; - } - try { - if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { - Intent intent = new Intent(); - intent.setComponent(new ComponentName("com.android.nfc", - "com.android.nfc.NfcBootstrapService")); - context.startServiceAsUser(intent, UserHandle.OWNER); - } - } catch (RemoteException e) { - Slog.w(TAG, "Package manager query failed, assuming no NFC feature", e); - return; - } - } } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 9c44c7a195f01..aa8b37fec713d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -27,6 +27,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.os.SystemProperties; +import android.os.UserHandle; import android.test.AndroidTestCase; import android.test.mock.MockContext; import android.text.TextUtils; @@ -365,7 +366,7 @@ public void testPrebundledDifferentRegionReject() { }; Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices)) .thenReturn(regionRestrictedPackages); - assertFalse(settings.shouldPrebundledPackageBeInstalled(resources, + assertFalse(settings.shouldPrebundledPackageBeInstalledForRegion(resources, expectedPackageNeededForRegion, resources)); } @@ -384,7 +385,70 @@ public void testPrebundledMatchingRegionAccept() { Mockito.when(resources.getStringArray(R.array.config_restrict_to_region_locked_devices)) .thenReturn(regionLockedPackages); - assertTrue(settings.shouldPrebundledPackageBeInstalled(resources, + assertTrue(settings.shouldPrebundledPackageBeInstalledForRegion(resources, expectedPackageNeededForRegion, resources)); } + + // Shamelessly kanged from KeySetManagerServiceTest + public PackageSetting generateFakePackageSetting(String name) { + return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"), + new File(mContext.getCacheDir(), "fakeResPath"), "", "", "", + "", 1, 0, 0); + } + + // Checks if a package that was installed and currently isn't installed for the owner + // is accepted for a secondary user + public void testPrebundledSecondaryUserAccept() { + Settings settings = new Settings(getContext().getFilesDir()); + String expectedPackageToBeInstalled = "org.cyanogenmod.secondaryuser.package"; + + PackageSetting packageSetting = + generateFakePackageSetting(expectedPackageToBeInstalled); + + int userOwner = UserHandle.USER_OWNER; + int userSecondary = 1000; + + // Return true that the package was installed for the owner at some point + settings.markPrebundledPackageInstalledLPr(userOwner, expectedPackageToBeInstalled); + assertTrue(settings.wasPrebundledPackageInstalledLPr(userOwner, + expectedPackageToBeInstalled)); + + // Return false that the package was installed for the secondary user at some point + // DON'T MARK PREBUNDLED PACKAGE INSTALLED + + // Return false that the package is currently not installed for the owner + packageSetting.setInstalled(false, userOwner); + assertFalse(packageSetting.getInstalled(userOwner)); + + // Return false that the package is currently not installed for the secondary user + packageSetting.setInstalled(false, userSecondary); + assertFalse(packageSetting.getInstalled(userSecondary)); + + assertFalse(settings.shouldPrebundledPackageBeInstalledForUserLPr(packageSetting, + userSecondary, expectedPackageToBeInstalled)); + } + + // Checks if a package that was installed for a secondary user and currently isn't installed + // for the user is accepted to be reinstalled + public void testPrebundledSecondaryUserReinstallAccept() { + Settings settings = new Settings(getContext().getFilesDir()); + String expectedPackageToBeInstalled = "org.cyanogenmod.secondaryuser.package"; + + PackageSetting packageSetting = + generateFakePackageSetting(expectedPackageToBeInstalled); + + int userSecondary = 1000; + + // Return true that the package was installed for the secondary user at some point + settings.markPrebundledPackageInstalledLPr(userSecondary, expectedPackageToBeInstalled); + assertTrue(settings.wasPrebundledPackageInstalledLPr(userSecondary, + expectedPackageToBeInstalled)); + + // Return false that the package is currently not installed for the secondary user + packageSetting.setInstalled(false, userSecondary); + assertFalse(packageSetting.getInstalled(userSecondary)); + + assertFalse(settings.shouldPrebundledPackageBeInstalledForUserLPr(packageSetting, + userSecondary, expectedPackageToBeInstalled)); + } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 3fecfb61b3412..2886ce6f608b3 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -580,7 +580,13 @@ private void updateCurrentAccessory() { if (mConfigured && enteringAccessoryMode) { // successfully entered accessory mode - + if (mCurrentAccessory != null) { + Slog.w(TAG, "USB accessory re-attached, detach was not announced!"); + if (mBootCompleted) { + getCurrentSettings().accessoryDetached(mCurrentAccessory); + } + mCurrentAccessory = null; + } if (mAccessoryStrings != null) { mCurrentAccessory = new UsbAccessory(mAccessoryStrings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); @@ -895,6 +901,7 @@ private void updateAdbNotification() { private String getDefaultFunctions() { String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE); + func = UsbManager.removeFunction(func, "charging"); if (UsbManager.USB_FUNCTION_NONE.equals(func)) { func = UsbManager.USB_FUNCTION_MTP; } diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 8af52f20b88e4..438e7bb42bd29 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -831,6 +831,16 @@ public void answer(int videoState) { mInCallAdapter.answerCall(mTelecomCallId, videoState); } + /** + * Instructs this {@link #STATE_RINGING} {@code Call} to answer. + * @param videoState The video state in which to answer the call. + * @param callWaitingResponseType Type of response for call waiting + * @hide + */ + public void answer(int videoState, int callWaitingResponseType) { + mInCallAdapter.answerCall(mTelecomCallId, videoState, callWaitingResponseType); + } + /** * Instructs this {@link #STATE_RINGING} {@code Call} to reject. * @@ -1172,6 +1182,7 @@ final void internalUpdate(ParcelableCall parcelableCall, Map callI && !parcelableCall.getCannedSmsResponses().isEmpty()) { mCannedTextResponses = Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); + cannedTextResponsesChanged = true; } boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 8eb62ec7307c3..d660f59a7db3e 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -56,6 +56,20 @@ public void answerCall(String callId, int videoState) { } } + /** + * Instructs Telecom to answer the specified call. + * + * @param callId The identifier of the call to answer. + * @param videoState The video state in which to answer the call. + * @param callWaitingResponseType Response type for call waiting. + */ + public void answerCall(String callId, int videoState, int callWaitingResponseType) { + try { + mAdapter.answerCallWithCallWaitingResponse(callId, videoState, callWaitingResponseType); + } catch (RemoteException e) { + } + } + /** * Instructs Telecom to reject the specified call. * diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index ae7c18eaa08a1..ca9792b51233a 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -443,6 +443,25 @@ public class TelecomManager { */ public static final int PRESENTATION_PAYPHONE = 4; + /** + * The following 2 constants define how the incoming call should be handled by the Telecomm + * server when there is already an active call. + */ + + /** + * Indicates that Telecom server should end the current active call when another incoming + * call is detected + * @hide + */ + public static final int CALL_WAITING_RESPONSE_NO_POPUP_END_CALL = 1; + + /** + * Indicates that Telecom server should hold the current active call when another incoming + * call is detected + * @hide + */ + public static final int CALL_WAITING_RESPONSE_NO_POPUP_HOLD_CALL = 2; + private static final String TAG = "TelecomManager"; private final Context mContext; diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 6ef8edaeedd47..3104fb27a6ccb 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -64,4 +64,7 @@ oneway interface IInCallAdapter { void switchToOtherActiveSub(String subId); void transferCall(String callId); + + void answerCallWithCallWaitingResponse(String callId, int videoState, int + callWaitingResponseType); } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index e1deb98cef595..74345e4990c96 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -543,7 +543,7 @@ public CarrierConfigManager() { sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false); sDefaults.putBoolean(KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL, true); sDefaults.putBoolean(KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL, true); - sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, true); + sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true); sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false); sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 86021e054f444..3b375e218cb8e 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1397,7 +1397,7 @@ public static Resources getResourcesForSubId(Context context, int subId) { newConfig.setTo(config); if (subInfo != null) { newConfig.mcc = subInfo.getMcc(); - newConfig.mnc = subInfo.getMnc(); + newConfig.mnc = subInfo.getMnc() == 0 ? Configuration.MNC_ZERO : subInfo.getMnc(); } DisplayMetrics metrics = context.getResources().getDisplayMetrics(); DisplayMetrics newMetrics = new DisplayMetrics(); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 7afaf7ec2a981..5ec6950d79930 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -3068,6 +3068,50 @@ public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) { return null; } + /** + * Opens a logical channel to the ICC card + * + * Input parameters equivalent to TS 27.007 AT+CCHO command. + * + * @param AID application id. See ETSI 102.221 and 101.220. + * @param p2 byte P2 parameter + * @return an IccOpenLogicalChannelResponse object + * @hide + */ + public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, byte p2) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccOpenLogicalChannelWithP2(AID, p2); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** + * Opens a logical channel to the ICC card for the given subId + * + * @param subId subid to send the command to + * @param AID applcation id. See ETSI 102.221 and 101.220. + * @param p2 byte P2 parameter + * @return an IccOpenLogicalChannelResponse object + * @hide + */ + public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, + String AID, byte p2) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.iccOpenLogicalChannelUsingSubIdWithP2(subId, AID, p2); + } + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + /** * Closes a previously opened logical channel to the ICC card. * diff --git a/telephony/java/com/android/internal/telephony/IExtTelephony.aidl b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl index f98a0d883f489..7040f8079f682 100644 --- a/telephony/java/com/android/internal/telephony/IExtTelephony.aidl +++ b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl @@ -123,4 +123,49 @@ interface IExtTelephony { * @return true or false */ boolean isFdnEnabled(); + + /** + * Get application count from card. + * @param - slotId user preferred slotId + * @return application count + */ + int getUiccApplicationCount(int slotId); + + /** + * Get application type by index. + * @param - slotId user preferred slotId + * - appIndex application index + * @return application type as Integer, below are + * supported return values: + * '0' - APPTYPE_UNKNOWN + * '1' - APPTYPE_SIM + * '2' - APPTYPE_USIM + * '3 - APPTYPE_RUIM + * '4' - APPTYPE_CSIM + * '5' - APPTYPE_ISIM + */ + int getUiccApplicationType(int slotId, int appIndex); + + /** + * Get application state by index. + * @param - slotId user preferred slotId + * - appIndex application index + * @return application state as Integer, below are + * supported return values: + * '0' - APPSTATE_UNKNOWN + * '1' - APPSTATE_DETECTED + * '2' - APPSTATE_PIN + * '3 - APPSTATE_PUK + * '4' - APPSTATE_SUBSCRIPTION_PERSO + * '5' - APPSTATE_READY + */ + int getUiccApplicationState(int slotId, int appIndex); + + /** + * Get primary stack phone id. + * @param - void + * @return phone id + */ + int getPrimaryStackPhoneId(); + } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index c3db8c26d114b..291ce275d4a85 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -570,6 +570,16 @@ interface ITelephony { */ IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID); + /** + * Opens a logical channel to the ICC card. + * + * Input parameters equivalent to TS 27.007 AT+CCHO command. + * + * @param p2 P2 parameter + * @param AID Application id. + * @return an IccOpenLogicalChannelResponse object. + */ + IccOpenLogicalChannelResponse iccOpenLogicalChannelWithP2(String AID, byte p2); /** * Opens a logical channel to the ICC card for a particular subId. @@ -582,6 +592,16 @@ interface ITelephony { */ IccOpenLogicalChannelResponse iccOpenLogicalChannelUsingSubId(int subId, String AID); + /** + * Opens a logical channel to the ICC card for a particular subID + * + * @param subId user preferred subId. + * @param p2 P2 parameter + * @param AID Application id. See ETSI 102.221 and 101.220 + */ + IccOpenLogicalChannelResponse iccOpenLogicalChannelUsingSubIdWithP2(int subId, + String AID, byte p2); + /** * Closes a previously opened logical channel to the ICC card. * diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 76b69cea8ae6b..ecb7dfe2abf8d 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -61,6 +61,8 @@ interface ITelephonyRegistry { void notifyCellInfo(in List cellInfo); void notifyPreciseCallState(int ringingCallState, int foregroundCallState, int backgroundCallState); + void notifyPreciseCallStateForSubscriber(int subId, int ringingCallState, + int foregroundCallState, int backgroundCallState); void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause); void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn, String failCause); diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index af79ff8ba8a5c..216dd38b8901a 100755 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -335,6 +335,8 @@ class C */ int RIL_REQUEST_PULL_LCEDATA = 134; int RIL_REQUEST_GET_ACTIVITY_INFO = 135; int RIL_REQUEST_SIM_GET_ATR = 136; + int RIL_REQUEST_CAF_SIM_OPEN_CHANNEL_WITH_P2 = 137; + int RIL_REQUEST_SET_MAX_TRANSMIT_POWER = 139; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index d3e2bfde86c77..bd0a89a94bd7b 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -904,7 +904,8 @@ public void setComponentProtectedSetting(ComponentName componentName, boolean ne * @hide */ @Override - public boolean isComponentProtected(String callingPackage, ComponentName componentName) { + public boolean isComponentProtected(String callingPackage, int callingUid, + ComponentName componentName) { throw new UnsupportedOperationException(); }