list, int callingUid, boolean allowed)
if (focusedStack && topTask) {
// Give the latest time to ensure foreground task can be sorted
// at the first, because lastActiveTime of creating task is 0.
- ci.lastActiveTime = System.currentTimeMillis();
+ // Only do this if the clock didn't run backwards, though.
+ ci.lastActiveTime = Math.max(ci.lastActiveTime, System.currentTimeMillis());
topTask = false;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index be90dc8b1d75e..bde32e7243a6e 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.
@@ -971,6 +956,40 @@ final int startActivityMayWait(IApplicationThread caller, int callingUid,
// Cannot start a child activity if the parent is not resumed.
return ActivityManager.START_CANCELED;
}
+
+ if (intent.getAction() != null && !isProvisioned()) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_SEARCH:
+ case Intent.ACTION_WEB_SEARCH:
+ case Intent.ACTION_PROCESS_TEXT:
+ case Intent.ACTION_ASSIST:
+ case Intent.ACTION_VOICE_ASSIST:
+ Slog.w(TAG, "not starting assist intent while not provisioned");
+ return ActivityManager.START_NOT_CURRENT_USER_ACTIVITY;
+ }
+ }
+ try {
+ //TODO: This needs to be a flushed out API in the future.
+ 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
+ intent.setFlags(startFlags);
+ intent.putExtra("com.android.settings.PROTECTED_APPS_USER_ID", userId);
+ msg.obj = intent;
+ mService.mHandler.sendMessage(msg);
+ return ActivityManager.START_NOT_CURRENT_USER_ACTIVITY;
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+
final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
@@ -1451,8 +1470,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;
@@ -1869,6 +1886,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;
@@ -2805,7 +2845,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) {
@@ -3090,15 +3130,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;
}
@@ -3907,7 +3947,9 @@ void removeLockedTaskLocked(final TaskRecord task) {
}
void showLockTaskToast() {
- mLockTaskNotify.showToast(mLockTaskModeState);
+ if (mLockTaskNotify != null) {
+ mLockTaskNotify.showToast(mLockTaskModeState);
+ }
}
void showLockTaskEscapeMessageLocked(TaskRecord task) {
@@ -4646,4 +4688,9 @@ private boolean isLeanbackOnlyDevice() {
return onLeanbackOnly;
}
+
+ private boolean isProvisioned() {
+ return Settings.Global.getInt(mService.mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+ }
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 62768c3b6475d..5fd3510683bf1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006-2007 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.
@@ -50,6 +51,8 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.DockBatteryStatsImpl;
+
import com.android.internal.os.PowerProfile;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -75,6 +78,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
static IBatteryStats sService;
final BatteryStatsImpl mStats;
+ // The dock stats only collect statistics about battery (no wakelocks, no counters, ...),
+ // just the dock battery history
+ final DockBatteryStatsImpl mDockStats;
final BatteryStatsHandler mHandler;
Context mContext;
PowerManagerInternal mPowerManagerInternal;
@@ -167,6 +173,7 @@ private void scheduleSyncLocked(String reason, int updateFlags) {
// BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
+ mDockStats = new DockBatteryStatsImpl(systemDir, handler, mHandler);
}
public void publish(Context context) {
@@ -196,6 +203,9 @@ public void shutdown() {
synchronized (mStats) {
mStats.shutdownLocked();
}
+ synchronized (mDockStats) {
+ mDockStats.shutdownLocked();
+ }
}
public static IBatteryStats getService() {
@@ -231,6 +241,16 @@ public void scheduleWriteToDisk() {
mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK);
}
+ /**
+ * @return the current dock statistics object, which may be modified
+ * to reflect events that affect battery usage. You must lock the
+ * stats object before doing anything with it.
+ * @hide
+ */
+ public BatteryStatsImpl getActiveDockStatistics() {
+ return mDockStats;
+ }
+
// These are for direct use by the activity manager...
/**
@@ -327,6 +347,48 @@ public boolean isCharging() {
}
}
+ /** @hide */
+ public byte[] getDockStatistics() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ //Slog.i("foo", "SENDING DOCK BATTERY INFO:");
+ //mDockStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
+ Parcel out = Parcel.obtain();
+ mDockStats.writeToParcel(out, 0);
+ byte[] data = out.marshall();
+ out.recycle();
+ return data;
+ }
+
+ /** @hide */
+ public ParcelFileDescriptor getDockStatisticsStream() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ //Slog.i("foo", "SENDING DOCK BATTERY INFO:");
+ //mDockStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
+ Parcel out = Parcel.obtain();
+ mDockStats.writeToParcel(out, 0);
+ byte[] data = out.marshall();
+ out.recycle();
+ try {
+ return ParcelFileDescriptor.fromData(data, "dock-battery-stats");
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to create shared memory", e);
+ return null;
+ }
+ }
+
+ public void resetStatistics() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.RESET_BATTERY_STATS, null);
+ synchronized (mStats) {
+ mStats.resetAllStatsCmdLocked();
+ }
+ synchronized (mDockStats) {
+ mDockStats.resetAllStatsCmdLocked();
+ }
+ }
+
public long computeBatteryTimeRemaining() {
synchronized (mStats) {
long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
@@ -901,6 +963,31 @@ public long getAwakeTimePlugged() {
return mStats.getAwakeTimePlugged();
}
+ /** @hide */
+ public boolean isOnDockBattery() {
+ return mDockStats.isOnBattery();
+ }
+
+ /** @hide */
+ public void setDockBatteryState(int status, int health, int plugType, int level,
+ int temp, int volt) {
+ enforceCallingPermission();
+ mDockStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ }
+
+ /** @hide */
+ public long getAwakeTimeDockBattery() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ return mDockStats.getAwakeTimeBattery();
+ }
+
+ public long getAwakeTimeDockPlugged() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ return mDockStats.getAwakeTimePlugged();
+ }
+
public void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
@@ -1065,6 +1152,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
} else if ("--reset".equals(arg)) {
synchronized (mStats) {
mStats.resetAllStatsCmdLocked();
+ mDockStats.resetAllStatsCmdLocked();
pw.println("Battery stats reset.");
noOutput = true;
}
@@ -1073,6 +1161,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
updateExternalStats("dump", UPDATE_ALL);
synchronized (mStats) {
mStats.writeSyncLocked();
+ mDockStats.writeSyncLocked();
pw.println("Battery stats written.");
noOutput = true;
}
@@ -1176,19 +1265,44 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mStats.mCheckinFile.getBaseFile(), e);
}
}
+ if (mDockStats.mCheckinFile.exists()) {
+ try {
+ byte[] raw = mDockStats.mCheckinFile.readFully();
+ if (raw != null) {
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, raw.length);
+ in.setDataPosition(0);
+ DockBatteryStatsImpl checkinStats = new DockBatteryStatsImpl(
+ null, mStats.mHandler, null);
+ checkinStats.readSummaryFromParcel(in);
+ in.recycle();
+ checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
+ historyStart);
+ mDockStats.mCheckinFile.delete();
+ return;
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure reading dock checkin file "
+ + mDockStats.mCheckinFile.getBaseFile(), e);
+ }
+ }
}
}
synchronized (mStats) {
mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
+ mDockStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
if (writeData) {
mStats.writeAsyncLocked();
+ mDockStats.writeAsyncLocked();
}
}
} else {
synchronized (mStats) {
mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
+ mDockStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
if (writeData) {
mStats.writeAsyncLocked();
+ mDockStats.writeAsyncLocked();
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 589a4b8555851..e7fec1944c63f 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -297,6 +297,11 @@ public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
final BroadcastRecord br = mPendingBroadcast;
if (br != null && br.curApp.pid == app.pid) {
+ if (br.curApp != app) {
+ Slog.e(TAG, "App mismatch when sending pending broadcast to "
+ + app.processName + ", intended target is " + br.curApp.processName);
+ return false;
+ }
try {
mPendingBroadcast = null;
processCurBroadcastLocked(br, app);
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index d1917db4be8c3..a5d37f01622d4 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -21,13 +21,13 @@
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
-import android.view.IWindowManager;
+import android.os.UserHandle;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.android.internal.R;
+import cyanogenmod.providers.CMSettings;
/**
* Helper to manage showing/hiding a image to notify them that they are entering
@@ -40,23 +40,19 @@ public class LockTaskNotify {
private final H mHandler;
private AccessibilityManager mAccessibilityManager;
private Toast mLastToast;
- private final IWindowManager mWindowManagerService;
public LockTaskNotify(Context context) {
mContext = context;
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mHandler = new H();
- mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
}
private boolean hasNavigationBar() {
- try {
- return mWindowManagerService.hasNavigationBar();
- } catch (RemoteException e) {
- //ignore
- }
- return false;
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_showNavigationBar)
+ || CMSettings.Global.getIntForUser(mContext.getContentResolver(),
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
}
public void showToast(int lockTaskModeState) {
@@ -67,9 +63,9 @@ public void handleShowToast(int lockTaskModeState) {
final int textResId;
if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) {
textResId = R.string.lock_to_app_toast_locked;
- } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) {
- textResId = mAccessibilityManager.isEnabled()
- ? R.string.lock_to_app_toast_accessible : R.string.lock_to_app_toast;
+ } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED &&
+ mAccessibilityManager.isEnabled() && hasNavigationBar()) {
+ textResId = R.string.lock_to_app_toast_accessible;
} else {
textResId = hasNavigationBar()
? R.string.lock_to_app_toast : R.string.lock_to_app_toast_no_navbar;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 9c9a42127a3f4..4def2fb9ceed7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -260,8 +260,8 @@ private void updateOomLevels(int displayWidth, int displayHeight, boolean write)
int maxSize = 1280*800; // 1024000 230400 870400 .264
float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
if (false) {
- Slog.i("XXXXXX", "scaleMem=" + scaleMem);
- Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth
+ Slog.i(TAG, "scaleMem=" + scaleMem);
+ Slog.i(TAG, "scaleDisp=" + scaleDisp + " dw=" + displayWidth
+ " dh=" + displayHeight);
}
@@ -273,7 +273,7 @@ private void updateOomLevels(int displayWidth, int displayHeight, boolean write)
int minfree_abs = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute);
if (false) {
- Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
+ Slog.i(TAG, "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
}
// We've now baked in the increase to the basic oom values above, since
@@ -286,12 +286,12 @@ private void updateOomLevels(int displayWidth, int displayHeight, boolean write)
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
- Slog.i("XXXXXX", "choosing minFree values for 64 Bit");
+ Slog.i(TAG, "choosing minFree values for 64 Bit");
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high*3)/2;
else if (i == 5) high = (high*7)/4;
} else {
- Slog.i("XXXXXX", "choosing minFree values for 32 Bit");
+ Slog.i(TAG, "choosing minFree values for 32 Bit");
low = mOomMinFreeLow32Bit[i];
high = mOomMinFreeHigh32Bit[i];
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 9cab95bfad9be..30f2c3ef7f650 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -136,6 +136,7 @@ final class ProcessRecord {
long curCpuTime; // How long proc has run CPU most recently
long lastRequestedGc; // When we last asked the app to do a gc
long lastLowMemory; // When we last told the app that memory is low
+ long lastProviderTime; // The last time someone else was using a provider in this process.
boolean reportLowMemory; // Set to true when waiting to report low mem
boolean empty; // Is this an empty background process?
boolean cached; // Is this a cached process?
@@ -317,6 +318,11 @@ void dump(PrintWriter pw, String prefix) {
pw.print(" foregroundActivities="); pw.print(foregroundActivities);
pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")");
}
+ if (lastProviderTime > 0) {
+ pw.print(prefix); pw.print("lastProviderTime=");
+ TimeUtils.formatDuration(lastProviderTime, now, pw);
+ pw.println();
+ }
if (hasStartedServices) {
pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices);
}
@@ -572,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/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c7e08bbb9a550..fe3df610e952d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -35,6 +35,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -126,6 +127,8 @@
import java.util.NoSuchElementException;
import java.util.Objects;
+import cyanogenmod.providers.CMSettings;
+
/**
* The implementation of the volume manager service.
*
@@ -583,11 +586,14 @@ private String makeDeviceListKey(int device, String deviceAddress) {
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
+ private boolean mLinkNotificationWithVolume;
+ private final boolean mVoiceCapable;
private static Long mLastDeviceConnectMsgTime = new Long(0);
private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
private long mLoweredFromNormalToVibrateTime;
+ private boolean mVolumeKeysControlRingStream;
// Intent "extra" data keys.
public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
@@ -640,6 +646,9 @@ public AudioService(Context context) {
mForcedUseForComm = AudioSystem.FORCE_NONE;
+ mVoiceCapable = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_voice_capable);
+
createAudioSystemThread();
AudioSystem.setErrorCallback(mAudioSystemCallback);
@@ -671,6 +680,10 @@ public AudioService(Context context) {
mForceAnalogCarDock = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_forceAnalogCarDock);
+ // read this in before readPersistedSettings() because updateStreamVolumeAlias needs it
+ mLinkNotificationWithVolume = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_LINK_NOTIFICATION, 1) == 1;
+
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
@@ -701,6 +714,7 @@ public AudioService(Context context) {
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ intentFilter.addAction(Intent.ACTION_SHUTDOWN);
// TODO merge orientation and rotation
mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
if (mMonitorOrientation) {
@@ -897,59 +911,63 @@ private void waitForAudioHandlerCreation() {
* @hide
*/
public void addMediaPlayerAndUpdateRemoteController (String packageName) {
- Log.v(TAG, "addMediaPlayerAndUpdateRemoteController: size of existing list: " +
- mMediaPlayers.size());
- boolean playerToAdd = true;
- if (mMediaPlayers.size() > 0) {
- final Iterator rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo player = rccIterator.next();
- if (packageName.equals(player.getPackageName())) {
- Log.e(TAG, "Player entry present, no need to add");
- playerToAdd = false;
- player.setFocus(true);
- } else {
- Log.e(TAG, "Player: " + player.getPackageName()+ "Lost Focus");
- player.setFocus(false);
+ synchronized(mMediaPlayers) {
+ Log.v(TAG, "addMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToAdd = true;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.e(TAG, "Player entry present, no need to add");
+ playerToAdd = false;
+ player.setFocus(true);
+ } else {
+ Log.e(TAG, "Player: " + player.getPackageName()+ "Lost Focus");
+ player.setFocus(false);
+ }
}
}
+ if (playerToAdd) {
+ Log.e(TAG, "Adding Player: " + packageName + " to available player list");
+ mMediaPlayers.add(new MediaPlayerInfo(packageName, true));
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, true);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating focussed RCC change to RCD: CallingPackageName:"
+ + packageName);
}
- if (playerToAdd) {
- Log.e(TAG, "Adding Player: " + packageName + " to available player list");
- mMediaPlayers.add(new MediaPlayerInfo(packageName, true));
- }
- Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
- intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, true);
- intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
- sendBroadcastToAll(intent);
- Log.v(TAG, "updating focussed RCC change to RCD: CallingPackageName:"
- + packageName);
}
/**
* @hide
*/
public void updateRemoteControllerOnExistingMediaPlayers() {
- Log.v(TAG, "updateRemoteControllerOnExistingMediaPlayers: size of Player list: " +
+ synchronized(mMediaPlayers) {
+ Log.v(TAG, "updateRemoteControllerOnExistingMediaPlayers: size of Player list: " +
mMediaPlayers.size());
- if (mMediaPlayers.size() > 0) {
- Log.v(TAG, "Inform RemoteController regarding existing RCC entry");
- final Iterator rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo player = rccIterator.next();
- Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME,
- player.getPackageName());
- intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,
- player.isFocussed());
- intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
- sendBroadcastToAll(intent);
- Log.v(TAG, "updating RCC change: CallingPackageName:" +
- player.getPackageName());
+ if (mMediaPlayers.size() > 0) {
+ Log.v(TAG, "Inform RemoteController regarding existing RCC entry");
+ final Iterator rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ final MediaPlayerInfo player = rccIterator.next();
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME,
+ player.getPackageName());
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,
+ player.isFocussed());
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, true);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "updating RCC change: CallingPackageName:" +
+ player.getPackageName());
+ }
+ } else {
+ Log.e(TAG, "No RCC entry present to update");
}
- } else {
- Log.e(TAG, "No RCC entry present to update");
}
}
@@ -957,34 +975,36 @@ public void updateRemoteControllerOnExistingMediaPlayers() {
* @hide
*/
public void removeMediaPlayerAndUpdateRemoteController (String packageName) {
- Log.v(TAG, "removeMediaPlayerAndUpdateRemoteController: size of existing list: " +
- mMediaPlayers.size());
- boolean playerToRemove = false;
- int index = -1;
- if (mMediaPlayers.size() > 0) {
- final Iterator rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- index++;
- final MediaPlayerInfo player = rccIterator.next();
- if (packageName.equals(player.getPackageName())) {
- Log.v(TAG, "Player entry present remove and update RemoteController");
- playerToRemove = true;
- break;
- } else {
- Log.v(TAG, "Player entry for " + player.getPackageName()+ " is not present");
+ synchronized(mMediaPlayers) {
+ Log.v(TAG, "removeMediaPlayerAndUpdateRemoteController: size of existing list: " +
+ mMediaPlayers.size());
+ boolean playerToRemove = false;
+ int index = -1;
+ if (mMediaPlayers.size() > 0) {
+ final Iterator rccIterator = mMediaPlayers.iterator();
+ while (rccIterator.hasNext()) {
+ index++;
+ final MediaPlayerInfo player = rccIterator.next();
+ if (packageName.equals(player.getPackageName())) {
+ Log.v(TAG, "Player entry present remove and update RemoteController");
+ playerToRemove = true;
+ break;
+ } else {
+ Log.v(TAG, "Player entry for " + player.getPackageName()+ " is not present");
+ }
}
}
+ if (playerToRemove) {
+ Log.e(TAG, "Removing Player: " + packageName + " from index" + index);
+ mMediaPlayers.remove(index);
+ }
+ Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
+ intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, false);
+ intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, false);
+ sendBroadcastToAll(intent);
+ Log.v(TAG, "Updated List size: " + mMediaPlayers.size());
}
- if (playerToRemove) {
- Log.e(TAG, "Removing Player: " + packageName + " from index" + index);
- mMediaPlayers.remove(index);
- }
- Intent intent = new Intent(AudioManager.RCC_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME, packageName);
- intent.putExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE, false);
- intent.putExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, false);
- sendBroadcastToAll(intent);
- Log.v(TAG, "Updated List size: " + mMediaPlayers.size());
}
private void checkAllAliasStreamVolumes() {
@@ -1080,6 +1100,13 @@ private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
}
mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
+
+ if (mLinkNotificationWithVolume && mVoiceCapable) {
+ mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+ } else {
+ mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
+ }
+
if (updateVolumes) {
mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
caller);
@@ -1150,8 +1177,15 @@ private void readPersistedSettings() {
updateRingerModeAffectedStreams();
readDockAudioSettings(cr);
+
+ mVolumeKeysControlRingStream = CMSettings.System.getIntForUser(cr,
+ CMSettings.System.VOLUME_KEYS_CONTROL_RING_STREAM, 1,
+ UserHandle.USER_CURRENT) == 1;
}
+ mLinkNotificationWithVolume = Settings.Secure.getInt(cr,
+ Settings.Secure.VOLUME_LINK_NOTIFICATION, 1) == 1;
+
mMuteAffectedStreams = System.getIntForUser(cr,
System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
UserHandle.USER_CURRENT);
@@ -3588,10 +3622,16 @@ private int getActiveStreamType(int suggestedStreamType) {
if (DEBUG_VOL)
Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
return AudioSystem.STREAM_MUSIC;
- } else {
+ } else {
+ if (mVolumeKeysControlRingStream) {
if (DEBUG_VOL)
Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
return AudioSystem.STREAM_RING;
+ } else {
+ if (DEBUG_VOL)
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC b/c default");
+ return AudioSystem.STREAM_MUSIC;
+ }
}
} else if (isAfMusicActiveRecently(0)) {
if (DEBUG_VOL)
@@ -3626,9 +3666,16 @@ private int getActiveStreamType(int suggestedStreamType) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
return AudioSystem.STREAM_MUSIC;
} else {
- if (DEBUG_VOL) Log.v(TAG,
- "getActiveStreamType: using STREAM_NOTIFICATION as default");
- return AudioSystem.STREAM_NOTIFICATION;
+ if (mVolumeKeysControlRingStream) {
+ if (DEBUG_VOL)
+ Log.v(TAG,
+ "getActiveStreamType: using STREAM_NOTIFICATION as default");
+ return AudioSystem.STREAM_NOTIFICATION;
+ } else {
+ if (DEBUG_VOL)
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC b/c default");
+ return AudioSystem.STREAM_MUSIC;
+ }
}
}
break;
@@ -3962,8 +4009,29 @@ public void applyDeviceVolume_syncVSS(int device) {
int index;
if (mIsMuted) {
index = 0;
- } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
- || ((device & mFullVolumeDevices) != 0)) {
+ } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
+ /* Special handling for Bluetooth Absolute Volume scenario
+ * If we send full audio gain, some accessories are too loud even at its lowest
+ * volume. We are not able to enumerate all such accessories, so here is the
+ * workaround from phone side.
+ * For the lowest volume steps 1 and 2, restrict audio gain to 50% and 75%.
+ * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
+ */
+ int i = (getIndex(device) + 5)/10;
+ if (i == 0) {
+ // 0% for volume 0
+ index = 0;
+ } else if (i == 1) {
+ // 50% for volume 1
+ index = (int)(mIndexMax * 0.5) /10;
+ } else if (i == 2) {
+ // 75% for volume 2
+ index = (int)(mIndexMax * 0.75) /10;
+ } else {
+ // otherwise, full gain
+ index = (mIndexMax + 5)/10;
+ }
+ } else if ((device & mFullVolumeDevices) != 0) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
@@ -4587,7 +4655,11 @@ public void handleMessage(Message msg) {
break;
case MSG_PLAY_SOUND_EFFECT:
- onPlaySoundEffect(msg.arg1, msg.arg2);
+ if (isStreamMute(AudioSystem.STREAM_SYSTEM)) {
+ Log.d(TAG, "Stream muted, skip playback");
+ } else {
+ onPlaySoundEffect(msg.arg1, msg.arg2);
+ }
break;
case MSG_BTA2DP_DOCK_TIMEOUT:
@@ -4705,6 +4777,10 @@ private class SettingsObserver extends ContentObserver {
Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
mContentResolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
+ mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.VOLUME_LINK_NOTIFICATION), false, this);
+ mContentResolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLUME_KEYS_CONTROL_RING_STREAM), false, this);
}
@Override
@@ -4723,6 +4799,17 @@ public void onChange(boolean selfChange) {
setRingerModeInt(getRingerModeInternal(), false);
}
readDockAudioSettings(mContentResolver);
+
+ boolean linkNotificationWithVolume = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.VOLUME_LINK_NOTIFICATION, 1) == 1;
+ if (linkNotificationWithVolume != mLinkNotificationWithVolume) {
+ mLinkNotificationWithVolume = linkNotificationWithVolume;
+ createStreamStates();
+ updateStreamVolumeAlias(true, TAG);
+ }
+ mVolumeKeysControlRingStream = CMSettings.System.getIntForUser(mContentResolver,
+ CMSettings.System.VOLUME_KEYS_CONTROL_RING_STREAM, 1,
+ UserHandle.USER_CURRENT) == 1;
}
}
}
@@ -5029,12 +5116,18 @@ private void sendDeviceConnectionIntent(int device, int state, String address,
connType = AudioRoutesInfo.MAIN_HEADSET;
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone", 1);
+ if (state == 1) {
+ startMusicPlayer();
+ }
} else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
device == AudioSystem.DEVICE_OUT_LINE) {
/*do apps care about line-out vs headphones?*/
connType = AudioRoutesInfo.MAIN_HEADPHONES;
intent.setAction(Intent.ACTION_HEADSET_PLUG);
intent.putExtra("microphone", 0);
+ if (state == 1) {
+ startMusicPlayer();
+ }
} else if (device == AudioSystem.DEVICE_OUT_HDMI ||
device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
connType = AudioRoutesInfo.MAIN_HDMI;
@@ -5067,6 +5160,23 @@ private void sendDeviceConnectionIntent(int device, int state, String address,
}
}
+ private void startMusicPlayer() {
+ boolean launchPlayer = CMSettings.System.getIntForUser(mContext.getContentResolver(),
+ CMSettings.System.HEADSET_CONNECT_PLAYER, 0, UserHandle.USER_CURRENT) != 0;
+ TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+
+ if (launchPlayer && !tm.isInCall()) {
+ try {
+ Intent playerIntent = new Intent(Intent.ACTION_MAIN);
+ playerIntent.addCategory(Intent.CATEGORY_APP_MUSIC);
+ playerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(playerIntent);
+ } catch (ActivityNotFoundException | IllegalArgumentException e) {
+ Log.w(TAG, "No music player Activity could be found");
+ }
+ }
+ }
+
private void onSetWiredDeviceConnectionState(int device, int state, String address,
String deviceName, String caller) {
if (DEBUG_DEVICES) {
@@ -5324,6 +5434,8 @@ public void onReceive(Context context, Intent intent) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
UserManagerService.getInstance().setSystemControlledUserRestriction(
UserManager.DISALLOW_RECORD_AUDIO, false, userId);
+ } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
+ AudioSystem.setParameters("dev_shutdown=true");
}
}
} // end class AudioServiceBroadcastReceiver
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 7d1da01b8ca6a..58c76ec7674a9 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -27,6 +27,7 @@
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -39,10 +40,10 @@
import com.android.net.IProxyCallback;
import com.android.net.IProxyPortListener;
import com.android.net.IProxyService;
-import com.android.server.IoThread;
import libcore.io.Streams;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
@@ -66,6 +67,7 @@ public class PacManager {
private static final int DELAY_1 = 0;
private static final int DELAY_4 = 3;
private static final int DELAY_LONG = 4;
+ private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
/** Keep these values up-to-date with ProxyService.java */
public static final String KEY_PROXY = "keyProxy";
@@ -123,15 +125,21 @@ public void run() {
}
};
+ private final HandlerThread mNetThread = new HandlerThread("android.pacmanager",
+ android.os.Process.THREAD_PRIORITY_DEFAULT);
+ private final Handler mNetThreadHandler;
+
class PacRefreshIntentReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
- IoThread.getHandler().post(mPacDownloader);
+ mNetThreadHandler.post(mPacDownloader);
}
}
public PacManager(Context context, Handler handler, int proxyMessage) {
mContext = context;
mLastPort = -1;
+ mNetThread.start();
+ mNetThreadHandler = new Handler(mNetThread.getLooper());
mPacRefreshIntent = PendingIntent.getBroadcast(
context, 0, new Intent(ACTION_PAC_REFRESH), 0);
@@ -199,7 +207,25 @@ public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
private static String get(Uri pacUri) throws IOException {
URL url = new URL(pacUri.toString());
URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
- return new String(Streams.readFully(urlConnection.getInputStream()));
+ long contentLength = -1;
+ try {
+ contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ if (contentLength > MAX_PAC_SIZE) {
+ throw new IOException("PAC too big: " + contentLength + " bytes");
+ }
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = urlConnection.getInputStream().read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ if (bytes.size() > MAX_PAC_SIZE) {
+ throw new IOException("PAC too big");
+ }
+ }
+ return bytes.toString();
}
private int getNextDelay(int currentDelay) {
@@ -267,7 +293,7 @@ private void bind() {
intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
if ((mProxyConnection != null) && (mConnection != null)) {
// Already bound no need to bind again, just download the new file.
- IoThread.getHandler().post(mPacDownloader);
+ mNetThreadHandler.post(mPacDownloader);
return;
}
mConnection = new ServiceConnection() {
@@ -297,7 +323,7 @@ public void onServiceConnected(ComponentName component, IBinder binder) {
} catch (RemoteException e) {
Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e);
}
- IoThread.getHandler().post(mPacDownloader);
+ mNetThreadHandler.post(mPacDownloader);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 9ead529b22ea0..60d677208c82b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -36,8 +36,11 @@
import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiDevice;
+import android.net.wifi.WifiManager;
import android.os.Binder;
+import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
@@ -56,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;
@@ -164,12 +168,16 @@ public class Tethering extends BaseNetworkObserver {
private static final int DNSMASQ_POLLING_INTERVAL = 1000;
private static final int DNSMASQ_POLLING_MAX_TIMES = 10;
+ private long mWiFiApInactivityTimeout;
+ private final Handler mHandler;
+
public Tethering(Context context, INetworkManagementService nmService,
INetworkStatsService statsService, Looper looper) {
mContext = context;
mNMService = nmService;
mStatsService = statsService;
mLooper = looper;
+ mHandler = new Handler(mLooper);
mPublicSync = new Object();
@@ -269,6 +277,18 @@ public void interfaceStatusChanged(String iface, boolean up) {
sm = new TetherInterfaceSM(iface, mLooper, usb);
mIfaces.put(iface, sm);
sm.start();
+ if (isWifi(iface)) {
+ // check if the user has specified an inactivity timeout for wifi AP and
+ // if so schedule the timeout
+ final WifiManager wm =
+ (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ final WifiConfiguration apConfig = wm.getWifiApConfiguration();
+ mWiFiApInactivityTimeout =
+ apConfig != null ? apConfig.wifiApInactivityTimeout : 0;
+ if (mWiFiApInactivityTimeout > 0 && mL2ConnectedDeviceMap.size() == 0) {
+ scheduleInactivityTimeout();
+ }
+ }
}
} else {
if (isUsb(iface)) {
@@ -278,6 +298,9 @@ public void interfaceStatusChanged(String iface, boolean up) {
} else if (sm != null) {
sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
mIfaces.remove(iface);
+ if (isWifi(iface)) {
+ cancelInactivityTimeout();
+ }
}
}
}
@@ -388,8 +411,6 @@ private void sendTetherConnectStateChangedBroadcast() {
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
-
- showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
}
private boolean readDeviceInfoFromDnsmasq(WifiDevice device) {
@@ -430,6 +451,29 @@ private boolean readDeviceInfoFromDnsmasq(WifiDevice device) {
return result;
}
+ private final Runnable mDisableWifiApRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (VDBG) Log.d(TAG, "Turning off hotpost due to inactivity");
+ final WifiManager wifiManager =
+ (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ wifiManager.setWifiApEnabled(null, false);
+ }
+ };
+
+ private void scheduleInactivityTimeout() {
+ if (mWiFiApInactivityTimeout > 0) {
+ if (VDBG) Log.d(TAG, "scheduleInactivityTimeout: " + mWiFiApInactivityTimeout);
+ mHandler.removeCallbacks(mDisableWifiApRunnable);
+ mHandler.postDelayed(mDisableWifiApRunnable, mWiFiApInactivityTimeout);
+ }
+ }
+
+ private void cancelInactivityTimeout() {
+ if (VDBG) Log.d(TAG, "cancelInactivityTimeout");
+ mHandler.removeCallbacks(mDisableWifiApRunnable);
+ }
+
/*
* DnsmasqThread is used to read the Device info from dnsmasq.
*/
@@ -513,10 +557,15 @@ public void interfaceMessageRecevied(String message) {
new DnsmasqThread(this, device,
DNSMASQ_POLLING_INTERVAL, DNSMASQ_POLLING_MAX_TIMES).start();
}
+ cancelInactivityTimeout();
} else if (device.deviceState == WifiDevice.DISCONNECTED) {
mL2ConnectedDeviceMap.remove(device.deviceAddress);
mConnectedDeviceMap.remove(device.deviceAddress);
sendTetherConnectStateChangedBroadcast();
+ // schedule inactivity timeout if non-zero and no more devices are connected
+ if (mWiFiApInactivityTimeout > 0 && mL2ConnectedDeviceMap.size() == 0) {
+ scheduleInactivityTimeout();
+ }
}
} catch (IllegalArgumentException ex) {
Log.e(TAG, "WifiDevice IllegalArgument: " + ex);
@@ -650,7 +699,12 @@ private void showTetheredNotification(int icon) {
if (mLastNotificationId != 0) {
if (mLastNotificationId == icon) {
- return;
+ if (!mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_softap_extention)
+ || icon != com.android.internal.R.drawable.stat_sys_tether_wifi) {
+ // if softap extension feature is on, allow to update icon else return.
+ return;
+ }
}
notificationManager.cancelAsUser(null, mLastNotificationId,
UserHandle.ALL);
@@ -666,24 +720,8 @@ private void showTetheredNotification(int icon) {
Resources r = Resources.getSystem();
CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
-
- CharSequence message;
- int size = mConnectedDeviceMap.size();
-
- if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)
- && icon == com.android.internal.R.drawable.stat_sys_tether_wifi) {
- if (size == 0) {
- message = r.getText(com.android.internal.R.string.tethered_notification_no_device_message);
- } else if (size == 1) {
- message = String.format((r.getText(com.android.internal.R.string.tethered_notification_one_device_message)).toString(),
- size);
- } else {
- message = String.format((r.getText(com.android.internal.R.string.tethered_notification_multi_device_message)).toString(),
- size);
- }
- } else {
- message = r.getText(com.android.internal.R.string.tethered_notification_message);
- }
+ CharSequence message = r.getText(com.android.internal.R.string.
+ tethered_notification_message);
if (mTetheredNotificationBuilder == null) {
mTetheredNotificationBuilder = new Notification.Builder(mContext);
@@ -698,18 +736,10 @@ private void showTetheredNotification(int icon) {
.setContentTitle(title)
.setContentText(message)
.setContentIntent(pi);
- if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_softap_extention)
- && icon == com.android.internal.R.drawable.stat_sys_tether_wifi
- && size > 0) {
- mTetheredNotificationBuilder.setContentText(message);
- } else {
- mTetheredNotificationBuilder.setContentTitle(title);
- }
mLastNotificationId = icon;
notificationManager.notifyAsUser(null, mLastNotificationId,
mTetheredNotificationBuilder.build(), UserHandle.ALL);
-
}
private void clearTetheredNotification() {
@@ -1566,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) {
@@ -1600,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/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index b766894d72b35..f581a7f8c4b7f 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -815,9 +815,13 @@ public List getCurrentSyncsAsUser(int userId) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ final boolean canAccessAccounts =
+ mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
+ == PackageManager.PERMISSION_GRANTED;
long identityToken = clearCallingIdentity();
try {
- return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
+ return getSyncManager().getSyncStorageEngine()
+ .getCurrentSyncsCopy(userId, canAccessAccounts);
} finally {
restoreCallingIdentity(identityToken);
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3ec0bee85f679..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.
@@ -2604,32 +2603,17 @@ private long maybeStartNextSyncH() {
}
continue;
}
- if (!isOperationValidLocked(op)) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- continue;
- }
- // If the next run time is in the future, even given the flexible scheduling,
- // return the time.
- if (op.effectiveRunTime - op.flexTime > now) {
- if (nextReadyToRunTime > op.effectiveRunTime) {
- nextReadyToRunTime = op.effectiveRunTime;
- }
- if (isLoggable) {
- Log.v(TAG, " Not running sync operation: Sync too far in future."
- + "effective: " + op.effectiveRunTime + " flex: " + op.flexTime
- + " now: " + now);
- }
- continue;
- }
String packageName = getPackageName(op.target);
ApplicationInfo ai = null;
if (packageName != null) {
try {
ai = mContext.getPackageManager().getApplicationInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
+ | PackageManager.GET_DISABLED_COMPONENTS);
} catch (NameNotFoundException e) {
+ operationIterator.remove();
+ mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ continue;
}
}
// If app is considered idle, then skip for now and backoff
@@ -2644,6 +2628,24 @@ private long maybeStartNextSyncH() {
} else {
op.appIdle = false;
}
+ if (!isOperationValidLocked(op)) {
+ operationIterator.remove();
+ mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ continue;
+ }
+ // If the next run time is in the future, even given the flexible scheduling,
+ // return the time.
+ if (op.effectiveRunTime - op.flexTime > now) {
+ if (nextReadyToRunTime > op.effectiveRunTime) {
+ nextReadyToRunTime = op.effectiveRunTime;
+ }
+ if (isLoggable) {
+ Log.v(TAG, " Not running sync operation: Sync too far in future."
+ + "effective: " + op.effectiveRunTime + " flex: " + op.flexTime
+ + " now: " + now);
+ }
+ continue;
+ }
// Add this sync to be run.
operations.add(op);
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index cca0c16f805fd..96a7bb47b5e28 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -45,6 +45,7 @@
import android.util.SparseArray;
import android.util.ArrayMap;
import android.util.Xml;
+import android.util.EventLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -1458,15 +1459,23 @@ private List getCurrentSyncs(int userId) {
}
/**
- * @return a copy of the current syncs data structure. Will not return
- * null.
+ * @param userId Id of user to return current sync info.
+ * @param canAccessAccounts Determines whether to redact Account information from the result.
+ * @return a copy of the current syncs data structure. Will not return null.
*/
- public List getCurrentSyncsCopy(int userId) {
+ public List getCurrentSyncsCopy(int userId, boolean canAccessAccounts) {
synchronized (mAuthorities) {
final List syncs = getCurrentSyncsLocked(userId);
final List syncsCopy = new ArrayList();
for (SyncInfo sync : syncs) {
- syncsCopy.add(new SyncInfo(sync));
+ SyncInfo copy;
+ if (!canAccessAccounts) {
+ copy = SyncInfo.createAccountRedacted(
+ sync.authorityId, sync.authority, sync.startTime);
+ } else {
+ copy = new SyncInfo(sync);
+ }
+ syncsCopy.add(copy);
}
return syncsCopy;
}
@@ -1892,8 +1901,13 @@ private void readAccountInfoLocked() {
if ("authority".equals(tagName)) {
authority = parseAuthority(parser, version);
periodicSync = null;
- if (authority.ident > highestAuthorityId) {
- highestAuthorityId = authority.ident;
+ if (authority != null) {
+ if (authority.ident > highestAuthorityId) {
+ highestAuthorityId = authority.ident;
+ }
+ } else {
+ EventLog.writeEvent(0x534e4554, "26513719", -1,
+ "Malformed authority");
}
} else if (XML_TAG_LISTEN_FOR_TICKLES.equals(tagName)) {
parseListenForTickles(parser);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 575701ac9b774..eca6a2e7c1944 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -55,18 +55,16 @@ class AutomaticBrightnessController {
// auto-brightness adjustment setting.
private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
- // Period of time in which to consider light samples in milliseconds.
- private static final int AMBIENT_LIGHT_HORIZON = 10000;
-
// Hysteresis constraints for brightening or darkening.
// The recent lux must have changed by at least this fraction relative to the
// current ambient lux before a change will be considered.
private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
- // The intercept used for the weighting calculation. This is used in order to keep all possible
- // weighting values positive.
- private static final int WEIGHTING_INTERCEPT = AMBIENT_LIGHT_HORIZON;
+ // Threshold (in lux) to select between normal and fast debounce time.
+ // If the difference between last sample and weighted value is larger than this value,
+ // fast debounce is used.
+ private static final float BRIGHTENING_FAST_THRESHOLD = 1000f;
// How long the current sensor reading is assumed to be valid beyond the current time.
// This provides a bit of prediction, as well as ensures that the weight for the last sample is
@@ -126,6 +124,7 @@ class AutomaticBrightnessController {
// when adapting to brighter or darker environments. This parameter controls how quickly
// brightness changes occur in response to an observed change in light level that exceeds the
// hysteresis threshold.
+ private final long mBrighteningLightFastDebounceConfig;
private final long mBrighteningLightDebounceConfig;
private final long mDarkeningLightDebounceConfig;
@@ -195,8 +194,12 @@ class AutomaticBrightnessController {
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
- // Night mode color temperature adjustments
- private final LiveDisplayController mLiveDisplay;
+ // Period of time in which to consider light samples in milliseconds.
+ private int mAmbientLightHorizon;
+
+ // The intercept used for the weighting calculation. This is used in order to keep all possible
+ // weighting values positive.
+ private int mWeightingIntercept;
private final Context mContext;
@@ -204,8 +207,9 @@ public AutomaticBrightnessController(Context context, Callbacks callbacks, Loope
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, long brighteningLightDebounceConfig,
- long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
- LiveDisplayController ldc) {
+ long brighteningLightFastDebounceConfig, long darkeningLightDebounceConfig,
+ boolean resetAmbientLuxAfterWarmUpConfig,
+ int ambientLightHorizon) {
mContext = context;
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
@@ -217,12 +221,14 @@ public AutomaticBrightnessController(Context context, Callbacks callbacks, Loope
mDozeScaleFactor = dozeScaleFactor;
mLightSensorRate = lightSensorRate;
mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
+ mBrighteningLightFastDebounceConfig = brighteningLightFastDebounceConfig;
mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
- mLiveDisplay = ldc;
+ mAmbientLightHorizon = ambientLightHorizon;
+ mWeightingIntercept = ambientLightHorizon;
mHandler = new AutomaticBrightnessHandler(looper);
- mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
+ mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -266,6 +272,7 @@ public void dump(PrintWriter pw) {
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
+ pw.println(" mBrighteningLightFastDebounceConfig=" + mBrighteningLightFastDebounceConfig);
pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
@@ -313,13 +320,14 @@ private boolean setLightSensorEnabled(boolean enable) {
private void handleLightSensorEvent(long time, float lux) {
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
+ if (DEBUG) Slog.d(TAG, "handleLightSensorEvent: time=" + time + ", lux=" + lux);
applyLightSensorMeasurement(time, lux);
updateAmbientLux(time);
}
private void applyLightSensorMeasurement(long time, float lux) {
mRecentLightSamples++;
- mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+ mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
// Remember this sample value.
@@ -370,17 +378,17 @@ private float calculateAmbientLux(long now) {
return sum / totalWeight;
}
- private static float calculateWeight(long startDelta, long endDelta) {
+ private float calculateWeight(long startDelta, long endDelta) {
return weightIntegral(endDelta) - weightIntegral(startDelta);
}
- // Evaluates the integral of y = x + WEIGHTING_INTERCEPT. This is always positive for the
+ // Evaluates the integral of y = x + mWeightIntercept. This is always positive for the
// horizon we're looking at and provides a non-linear weighting for light samples.
- private static float weightIntegral(long x) {
- return x * (x * 0.5f + WEIGHTING_INTERCEPT);
+ private float weightIntegral(long x) {
+ return x * (x * 0.5f + mWeightingIntercept);
}
- private long nextAmbientLightBrighteningTransition(long time) {
+ private long nextAmbientLightBrighteningTransition(long time, float ambientLux) {
final int N = mAmbientLightRingBuffer.size();
long earliestValidTime = time;
for (int i = N - 1; i >= 0; i--) {
@@ -389,10 +397,13 @@ private long nextAmbientLightBrighteningTransition(long time) {
}
earliestValidTime = mAmbientLightRingBuffer.getTime(i);
}
- return earliestValidTime + mBrighteningLightDebounceConfig;
+
+ long debounceDelay = mLastObservedLux - ambientLux > BRIGHTENING_FAST_THRESHOLD
+ ? mBrighteningLightFastDebounceConfig : mBrighteningLightDebounceConfig;
+ return earliestValidTime + debounceDelay;
}
- private long nextAmbientLightDarkeningTransition(long time) {
+ private long nextAmbientLightDarkeningTransition(long time, float ambientLux) {
final int N = mAmbientLightRingBuffer.size();
long earliestValidTime = time;
for (int i = N - 1; i >= 0; i--) {
@@ -406,7 +417,7 @@ private long nextAmbientLightDarkeningTransition(long time) {
private void updateAmbientLux() {
long time = SystemClock.uptimeMillis();
- mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+ mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
updateAmbientLux(time);
}
@@ -436,13 +447,12 @@ private void updateAmbientLux(long time) {
updateAutoBrightness(true);
}
- long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
- long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
float ambientLux = calculateAmbientLux(time);
+ long nextBrightenTransition = nextAmbientLightBrighteningTransition(time, ambientLux);
+ long nextDarkenTransition = nextAmbientLightDarkeningTransition(time, ambientLux);
if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
|| ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
- setAmbientLux(ambientLux);
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: "
+ ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
@@ -450,9 +460,10 @@ private void updateAmbientLux(long time) {
+ ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ ", mAmbientLux=" + mAmbientLux);
}
+ setAmbientLux(ambientLux);
updateAutoBrightness(true);
- nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
- nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
+ nextBrightenTransition = nextAmbientLightBrighteningTransition(time, ambientLux);
+ nextDarkenTransition = nextAmbientLightDarkeningTransition(time, ambientLux);
}
long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
// If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
@@ -488,9 +499,6 @@ private void updateAutoBrightness(boolean sendUpdate) {
}
}
- // Update LiveDisplay with the current lux
- mLiveDisplay.updateLiveDisplay(mAmbientLux);
-
if (USE_TWILIGHT_ADJUSTMENT) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
@@ -666,8 +674,8 @@ private static final class AmbientLightRingBuffer{
private int mEnd;
private int mCount;
- public AmbientLightRingBuffer(long lightSensorRate) {
- mCapacity = (int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate);
+ public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
+ mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
mRingLux = new float[mCapacity];
mRingTime = new long[mCapacity];
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e8a857bb07505..6a6570b97205c 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -287,8 +287,6 @@ public void systemReady(boolean safeMode, boolean onlyCore) {
mOnlyCore = onlyCore;
}
- mDisplayPowerController.systemReady();
-
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 38c418043835e..25e59d55341ca 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -251,9 +251,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The controller for the automatic brightness level.
private AutomaticBrightnessController mAutomaticBrightnessController;
- // The controller for LiveDisplay
- private final LiveDisplayController mLiveDisplayController;
-
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -275,8 +272,6 @@ public DisplayPowerController(Context context,
mBlanker = blanker;
mContext = context;
- mLiveDisplayController = new LiveDisplayController(context, handler.getLooper());
-
final Resources resources = context.getResources();
final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
@@ -317,10 +312,14 @@ public DisplayPowerController(Context context,
com.android.internal.R.integer.config_autoBrightnessLightSensorRate);
long brighteningLightDebounce = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessBrighteningLightDebounce);
+ long brighteningLightFastDebounce = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessBrighteningLightFastDebounce);
long darkeningLightDebounce = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessDarkeningLightDebounce);
boolean autoBrightnessResetAmbientLuxAfterWarmUp = resources.getBoolean(
com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp);
+ int ambientLightHorizon = resources.getInteger(
+ com.android.internal.R.integer.config_autoBrightnessAmbientLightHorizon);
if (mUseSoftwareAutoBrightnessConfig) {
int[] lux = resources.getIntArray(
@@ -357,8 +356,9 @@ public DisplayPowerController(Context context,
handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
- brighteningLightDebounce, darkeningLightDebounce,
- autoBrightnessResetAmbientLuxAfterWarmUp, mLiveDisplayController);
+ brighteningLightDebounce, brighteningLightFastDebounce,
+ darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
+ ambientLightHorizon);
}
}
@@ -711,9 +711,6 @@ private void updatePowerState() {
}
}
- // Update LiveDisplay now
- mLiveDisplayController.updateLiveDisplay();
-
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
@@ -1152,8 +1149,6 @@ private void dumpLocal(PrintWriter pw) {
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.dump(pw);
}
-
- mLiveDisplayController.dump(pw);
}
private static String proximityToString(int state) {
@@ -1215,10 +1210,6 @@ private static int clampAbsoluteBrightness(int value) {
return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
- void systemReady() {
- mLiveDisplayController.systemReady();
- }
-
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/display/LiveDisplayController.java b/services/core/java/com/android/server/display/LiveDisplayController.java
deleted file mode 100644
index 9e6da2ddd1cde..0000000000000
--- a/services/core/java/com/android/server/display/LiveDisplayController.java
+++ /dev/null
@@ -1,834 +0,0 @@
-/*
- * Copyright (C) 2015 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.server.display;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.PowerManagerInternal;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.MathUtils;
-import android.util.Slog;
-
-import com.android.server.LocalServices;
-import com.android.server.accessibility.DisplayAdjustmentUtils;
-import com.android.server.twilight.TwilightListener;
-import com.android.server.twilight.TwilightManager;
-import com.android.server.twilight.TwilightState;
-
-import cyanogenmod.hardware.CMHardwareManager;
-import cyanogenmod.providers.CMSettings;
-
-import java.io.PrintWriter;
-
-public class LiveDisplayController {
-
- private static final String TAG = "LiveDisplay";
-
- private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 1;
-
- private static final int OFF_TEMPERATURE = 6500;
-
- public static final int MODE_OFF = 0;
- public static final int MODE_NIGHT = 1;
- public static final int MODE_AUTO = 2;
- public static final int MODE_OUTDOOR = 3;
- public static final int MODE_DAY = 4;
-
- private int mColorTemperature = OFF_TEMPERATURE;
- private float mCurrentLux = 0.0f;
-
- private int mHintCounter;
- private int mMode;
-
- private boolean mOutdoorMode;
- private boolean mColorEnhancement;
- private boolean mLowPower;
-
- private final Context mContext;
- private final Handler mHandler;
-
- private CMHardwareManager mHardware;
-
- private int mDayTemperature;
- private int mNightTemperature;
-
- private boolean mUseOutdoorMode;
- private boolean mUseColorEnhancement;
- private boolean mUseLowPower;
-
- private boolean mOutdoorModeIsSelfManaged;
-
- private final float[] mColorAdjustment = new float[] { 1.0f, 1.0f, 1.0f };
- private final float[] mRGB = new float[] { 0.0f, 0.0f, 0.0f };
-
- private TwilightManager mTwilightManager;
- private boolean mSunset = false;
-
- private SettingsObserver mObserver;
-
- private ValueAnimator mAnimator;
-
- private int mDefaultDayTemperature;
- private int mDefaultNightTemperature;
- private int mDefaultOutdoorLux;
-
- private boolean mInitialized = false;
-
- private static final int MSG_UPDATE_LIVE_DISPLAY = 1;
-
- // Display postprocessing can have power impact. Disable it if powersave mode is on.
- private boolean mLowPerformance = false;
- private PowerManagerInternal.LowPowerModeListener mLowPowerModeListener =
- new PowerManagerInternal.LowPowerModeListener() {
- @Override
- public void onLowPowerModeChanged(boolean enabled) {
- mLowPerformance = enabled;
- updateLiveDisplay(mCurrentLux);
- }
- };
-
- LiveDisplayController(Context context, Looper looper) {
- mContext = context;
- mHandler = new LiveDisplayHandler(looper);
- }
-
- void systemReady() {
- mHardware = CMHardwareManager.getInstance(mContext);
-
- mDefaultDayTemperature = mContext.getResources().getInteger(
- org.cyanogenmod.platform.internal.R.integer.config_dayColorTemperature);
- mDefaultNightTemperature = mContext.getResources().getInteger(
- org.cyanogenmod.platform.internal.R.integer.config_nightColorTemperature);
- mDefaultOutdoorLux = mContext.getResources().getInteger(
- org.cyanogenmod.platform.internal.R.integer.config_outdoorAmbientLux);
-
- // Counter used to determine when we should tell the user about this feature.
- // If it's not used after 3 sunsets, we'll show the hint once.
- mHintCounter = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.LIVE_DISPLAY_HINTED,
- -3,
- UserHandle.USER_CURRENT);
-
- mUseOutdoorMode =
- mHardware.isSupported(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT);
- mOutdoorModeIsSelfManaged = mUseOutdoorMode ?
- mHardware.isSunlightEnhancementSelfManaged() : false;
-
- mUseLowPower =
- mHardware.isSupported(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
- if (mUseLowPower) {
- mLowPower = mHardware.get(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT);
- }
-
- mUseColorEnhancement =
- mHardware.isSupported(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
- if (mUseColorEnhancement) {
- mColorEnhancement =
- mHardware.get(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT);
- }
-
- updateSettings();
-
- mObserver = new SettingsObserver();
- mObserver.register(true);
-
- PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
- pmi.registerLowPowerModeObserver(mLowPowerModeListener);
- mLowPerformance = pmi.getLowPowerModeEnabled();
-
- mTwilightManager = LocalServices.getService(TwilightManager.class);
- mTwilightManager.registerListener(mTwilightListener, mHandler);
-
- mInitialized = true;
- }
-
- private void updateSettings() {
- mDayTemperature = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_DAY,
- mDefaultDayTemperature,
- UserHandle.USER_CURRENT);
- mNightTemperature = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_NIGHT,
- mDefaultNightTemperature,
- UserHandle.USER_CURRENT);
- mMode = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_TEMPERATURE_MODE,
- MODE_OFF,
- UserHandle.USER_CURRENT);
-
- // Clear the hint forever
- if (mMode != MODE_OFF) {
- saveUserHint(1);
- }
-
- // Manual color adjustment will be set as a space separated string of float values
- String colorAdjustmentTemp = CMSettings.System.getStringForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_COLOR_ADJUSTMENT,
- UserHandle.USER_CURRENT);
- String[] colorAdjustment = colorAdjustmentTemp == null ?
- null : colorAdjustmentTemp.split(" ");
- if (colorAdjustment == null || colorAdjustment.length != 3) {
- colorAdjustment = new String[] { "1.0", "1.0", "1.0" };
- }
- try {
- mColorAdjustment[0] = Float.parseFloat(colorAdjustment[0]);
- mColorAdjustment[1] = Float.parseFloat(colorAdjustment[1]);
- mColorAdjustment[2] = Float.parseFloat(colorAdjustment[2]);
- } catch (NumberFormatException e) {
- Slog.e(TAG, e.getMessage(), e);
- mColorAdjustment[0] = 1.0f;
- mColorAdjustment[1] = 1.0f;
- mColorAdjustment[2] = 1.0f;
- }
-
- updateLiveDisplay(mCurrentLux);
- }
-
- private final class SettingsObserver extends ContentObserver {
- private final Uri DISPLAY_TEMPERATURE_DAY_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_DAY);
- private final Uri DISPLAY_TEMPERATURE_NIGHT_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_NIGHT);
- private final Uri DISPLAY_TEMPERATURE_MODE_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_TEMPERATURE_MODE);
- private final Uri DISPLAY_AUTO_OUTDOOR_MODE_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE);
- private final Uri DISPLAY_LOW_POWER_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_LOW_POWER);
- private final Uri DISPLAY_COLOR_ENHANCE_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ENHANCE);
- private final Uri DISPLAY_COLOR_ADJUSTMENT_URI =
- CMSettings.System.getUriFor(CMSettings.System.DISPLAY_COLOR_ADJUSTMENT);
- public SettingsObserver() {
- super(mHandler);
- }
-
- public void register(boolean register) {
- final ContentResolver cr = mContext.getContentResolver();
- if (register) {
- cr.registerContentObserver(DISPLAY_TEMPERATURE_DAY_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_TEMPERATURE_NIGHT_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_TEMPERATURE_MODE_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_AUTO_OUTDOOR_MODE_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_LOW_POWER_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_COLOR_ENHANCE_URI, false, this, UserHandle.USER_ALL);
- cr.registerContentObserver(DISPLAY_COLOR_ADJUSTMENT_URI, false, this, UserHandle.USER_ALL);
- } else {
- cr.unregisterContentObserver(this);
- }
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- super.onChange(selfChange, uri);
- updateSettings();
- }
- }
-
- public void updateLiveDisplay() {
- updateLiveDisplay(mCurrentLux);
- }
-
- synchronized void updateLiveDisplay(float lux) {
- mCurrentLux = lux;
- mHandler.removeMessages(MSG_UPDATE_LIVE_DISPLAY);
- mHandler.sendEmptyMessage(MSG_UPDATE_LIVE_DISPLAY);
- }
-
- private synchronized void updateColorTemperature(TwilightState twilight) {
- int temperature = mDayTemperature;
- if (mMode == MODE_OFF || mLowPerformance) {
- temperature = OFF_TEMPERATURE;
- } else if (mMode == MODE_NIGHT) {
- temperature = mNightTemperature;
- } else if (mMode == MODE_AUTO) {
- temperature = getTwilightK(twilight);
- }
-
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- mAnimator = ValueAnimator.ofInt(mColorTemperature, temperature);
- mAnimator.setDuration(Math.abs(mColorTemperature - temperature) / 2);
- mAnimator.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setDisplayTemperature((Integer)animation.getAnimatedValue());
- }
- });
- mAnimator.start();
- }
-
- private synchronized void setDisplayTemperature(int temperature) {
- mColorTemperature = temperature;
-
- final float[] rgb = temperatureToRGB(temperature);
-
- if (!mLowPerformance) {
- rgb[0] *= mColorAdjustment[0];
- rgb[1] *= mColorAdjustment[1];
- rgb[2] *= mColorAdjustment[2];
- }
-
- if (rgb[0] == mRGB[0] && rgb[1] == mRGB[1] && rgb[2] == mRGB[2]) {
- // no changes
- return;
- }
-
- System.arraycopy(rgb, 0, mRGB, 0, 3);
-
- Slog.d(TAG, "Adjust display temperature to " + temperature +
- "K [r=" + rgb[0] + " g=" + rgb[1] + " b=" + rgb[2] + "]");
-
- if (mHardware.isSupported(CMHardwareManager.FEATURE_DISPLAY_COLOR_CALIBRATION)) {
- // Clear this out in case of an upgrade
- CMSettings.Secure.putStringForUser(mContext.getContentResolver(),
- CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
- null,
- UserHandle.USER_CURRENT);
-
- int max = mHardware.getDisplayColorCalibrationMax();
- mHardware.setDisplayColorCalibration(new int[] {
- (int) Math.ceil(rgb[0] * max),
- (int) Math.ceil(rgb[1] * max),
- (int) Math.ceil(rgb[2] * max)
- });
- screenRefresh();
- } else {
- String colorMatrixStr = null;
- if (rgb[0] != 1.0f || rgb[1] != 1.0f || rgb[2] != 1.0f) {
- final Float[] colorMatrix = new Float[] {
- rgb[0], 0.0f, 0.0f, 0.0f,
- 0.0f, rgb[1], 0.0f, 0.0f,
- 0.0f, 0.0f, rgb[2], 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f };
- colorMatrixStr = TextUtils.join(" ", colorMatrix);
- }
-
- // For GPU color transform, go thru DisplayAdjustmentUtils in
- // order to coexist with accessibility settings
- CMSettings.Secure.putStringForUser(mContext.getContentResolver(),
- CMSettings.Secure.LIVE_DISPLAY_COLOR_MATRIX,
- colorMatrixStr,
- UserHandle.USER_CURRENT);
-
- DisplayAdjustmentUtils.applyAdjustments(mContext, UserHandle.USER_CURRENT);
- }
- }
-
- /**
- * Outdoor mode is optionally enabled when ambient lux > 10000 and it's daytime
- * Melt faces!
- *
- * TODO: Use the camera or RGB sensor to determine if it's really sunlight
- */
- private synchronized void updateOutdoorMode(TwilightState twilight) {
- if (!mUseOutdoorMode) {
- return;
- }
-
- boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_AUTO_OUTDOOR_MODE,
- 1,
- UserHandle.USER_CURRENT) == 1;
-
- boolean enabled;
- if (mOutdoorModeIsSelfManaged) {
- enabled = value;
- } else {
- enabled = !mLowPerformance &&
- ((mMode == MODE_OUTDOOR) ||
- (value && mMode == MODE_AUTO &&
- twilight != null && !twilight.isNight() &&
- mCurrentLux > mDefaultOutdoorLux));
- }
-
- if (enabled == mOutdoorMode) {
- return;
- }
-
- mHardware.set(CMHardwareManager.FEATURE_SUNLIGHT_ENHANCEMENT, enabled);
- mOutdoorMode = enabled;
- }
-
- /**
- * Color enhancement is optional, but can look bad with night mode
- */
- private synchronized void updateColorEnhancement(TwilightState twilight) {
- if (!mUseColorEnhancement) {
- return;
- }
-
- boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_COLOR_ENHANCE,
- 1,
- UserHandle.USER_CURRENT) == 1;
-
- boolean enabled = !mLowPerformance && value &&
- !(mMode == MODE_NIGHT ||
- (mMode == MODE_AUTO && twilight != null && twilight.isNight()));
-
- if (enabled == mColorEnhancement) {
- return;
- }
-
- mHardware.set(CMHardwareManager.FEATURE_COLOR_ENHANCEMENT, enabled);
- mColorEnhancement = enabled;
- }
-
- /**
- * Adaptive backlight / low power mode. Turn it off when under very bright light.
- */
- private synchronized void updateLowPowerMode() {
- if (!mUseLowPower) {
- return;
- }
-
- boolean value = CMSettings.System.getIntForUser(mContext.getContentResolver(),
- CMSettings.System.DISPLAY_LOW_POWER,
- 1,
- UserHandle.USER_CURRENT) == 1;
-
- boolean enabled = value && (mCurrentLux < mDefaultOutdoorLux);
-
- if (enabled == mLowPower) {
- return;
- }
-
- mHardware.set(CMHardwareManager.FEATURE_ADAPTIVE_BACKLIGHT, enabled);
- mLowPower = enabled;
- }
-
- /**
- * Convert a color temperature value (in Kelvin) to a RGB units as floats.
- * This can be used in a transform matrix or hardware gamma control.
- *
- * @param tempK
- * @return
- */
- private static float[] temperatureToRGB(int degreesK) {
- int k = MathUtils.constrain(degreesK, 1000, 20000);
- float a = (k % 100) / 100.0f;
- int i = ((k - 1000)/ 100) * 3;
-
- return new float[] { interp(i, a), interp(i+1, a), interp(i+2, a) };
- }
-
- private static float interp(int i, float a) {
- return MathUtils.lerp((float)sColorTable[i], (float)sColorTable[i+3], a);
- }
-
- /**
- * Where is the sun anyway? This calculation determines day or night, and scales
- * the value around sunset/sunrise for a smooth transition.
- *
- * @param now
- * @param sunset
- * @param sunrise
- * @return float between 0 and 1
- */
- private static float adj(long now, long sunset, long sunrise) {
- if (sunset < 0 || sunrise < 0
- || now < sunset || now > sunrise) {
- return 1.0f;
- }
-
- if (now < sunset + TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, 0.0f,
- (float)(now - sunset) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- if (now > sunrise - TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, 0.0f,
- (float)(sunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- return 0.0f;
- }
-
- /**
- * Determine the color temperature we should use for the display based on
- * the position of the sun.
- *
- * @param state
- * @return color temperature in Kelvin
- */
- private int getTwilightK(TwilightState state) {
- float adjustment = 1.0f;
-
- if (state != null) {
- final long now = System.currentTimeMillis();
- adjustment = adj(now, state.getYesterdaySunset(), state.getTodaySunrise()) *
- adj(now, state.getTodaySunset(), state.getTomorrowSunrise());
- }
-
- return (int)MathUtils.lerp(mNightTemperature, mDayTemperature, adjustment);
- }
-
- /**
- * Tell SurfaceFlinger to repaint the screen. This is called after updating
- * hardware registers for display calibration to have an immediate effect.
- */
- private static void screenRefresh() {
- try {
- final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
- if (flinger != null) {
- final Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- flinger.transact(1004, data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Failed to refresh screen", ex);
- }
- }
-
- private void saveUserHint(int value) {
- if (mHintCounter == value) {
- return;
- }
- CMSettings.System.putIntForUser(mContext.getContentResolver(),
- CMSettings.System.LIVE_DISPLAY_HINTED,
- value,
- UserHandle.USER_CURRENT);
- mHintCounter = value;
- }
-
- /**
- * Show a friendly notification to the user about the potential benefits of decreasing
- * blue light at night. Do this only once if the feature has not been used after
- * three sunsets. It would be great to enable this by default, but we don't want
- * the change of screen color to be considered a "bug" by a user who doesn't
- * understand what's happening.
- *
- * @param state
- */
- private void updateUserHint(TwilightState state) {
- // check if we should send the hint only once after sunset
- if (state == null || mHintCounter == 1) {
- return;
- }
- boolean transition = state.isNight() && !mSunset;
- mSunset = state.isNight();
- if (!transition) {
- return;
- }
-
- if (mHintCounter <= 0) {
- mHintCounter++;
- saveUserHint(mHintCounter);
- }
- if (mHintCounter == 0) {
- //show the notification and don't come back here
- final Intent intent = new Intent("android.settings.LIVEDISPLAY_SETTINGS");
- PendingIntent result = PendingIntent.getActivity(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- Notification.Builder builder = new Notification.Builder(mContext)
- .setContentTitle(mContext.getResources().getString(
- org.cyanogenmod.platform.internal.R.string.live_display_title))
- .setContentText(mContext.getResources().getString(
- org.cyanogenmod.platform.internal.R.string.live_display_hint))
- .setSmallIcon(org.cyanogenmod.platform.internal.R.drawable.ic_livedisplay_notif)
- .setStyle(new Notification.BigTextStyle().bigText(mContext.getResources()
- .getString(
- org.cyanogenmod.platform.internal.R.string.live_display_hint)))
- .setContentIntent(result);
-
- NotificationManager nm =
- (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notifyAsUser(null, 1, builder.build(), UserHandle.CURRENT);
-
- saveUserHint(1);
- }
- }
-
- private final TwilightListener mTwilightListener = new TwilightListener() {
- @Override
- public void onTwilightStateChanged() {
- updateLiveDisplay(mCurrentLux);
- }
- };
-
- private final class LiveDisplayHandler extends Handler {
- public LiveDisplayHandler(Looper looper) {
- super(looper, null, true /*async*/);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_LIVE_DISPLAY:
- if (!mInitialized) {
- break;
- }
- TwilightState twilight = mTwilightManager.getCurrentState();
-
- updateColorTemperature(twilight);
- updateOutdoorMode(twilight);
- updateColorEnhancement(twilight);
- updateLowPowerMode();
- updateUserHint(twilight);
-
- boolean transition = mMode == MODE_AUTO &&
- mColorTemperature != mDayTemperature &&
- mColorTemperature != mNightTemperature;
- if (transition) {
- // fire again in a minute
- sendEmptyMessageDelayed(MSG_UPDATE_LIVE_DISPLAY,
- DateUtils.MINUTE_IN_MILLIS);
- }
- break;
- }
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.println();
- pw.println("LiveDisplay Controller Configuration:");
- pw.println(" mDayTemperature=" + mDayTemperature);
- pw.println(" mNightTemperature=" + mNightTemperature);
- pw.println();
- pw.println("LiveDisplay Controller State:");
- pw.println(" mMode=" + (mLowPerformance ? "disabled in powersave mode" : mMode));
- pw.println(" mSunset=" + mSunset);
- pw.println(" mColorTemperature=" + mColorTemperature);
- pw.println(" mColorAdjustment=[r: " + mColorAdjustment[0] + " g:" + mColorAdjustment[1] +
- " b:" + mColorAdjustment[2] + "]");
- pw.println(" mRGB=[r:" + mRGB[0] + " g:" + mRGB[1] + " b:" + mRGB[2] + "]");
- pw.println(" mOutdoorMode=" + (mUseOutdoorMode ? mOutdoorMode : "N/A"));
- pw.println(" mColorEnhancement=" + (mUseColorEnhancement ? mColorEnhancement : "N/A"));
- pw.println(" mLowPower=" + (mUseLowPower ? mLowPower : "N/A"));
- }
-
- /**
- * This table is a modified version of the original blackbody chart, found here:
- * http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html
- *
- * Created by Ingo Thiel.
- */
- private static final double[] sColorTable = new double[] {
- 1.00000000, 0.18172716, 0.00000000,
- 1.00000000, 0.25503671, 0.00000000,
- 1.00000000, 0.30942099, 0.00000000,
- 1.00000000, 0.35357379, 0.00000000,
- 1.00000000, 0.39091524, 0.00000000,
- 1.00000000, 0.42322816, 0.00000000,
- 1.00000000, 0.45159884, 0.00000000,
- 1.00000000, 0.47675916, 0.00000000,
- 1.00000000, 0.49923747, 0.00000000,
- 1.00000000, 0.51943421, 0.00000000,
- 1.00000000, 0.54360078, 0.08679949,
- 1.00000000, 0.56618736, 0.14065513,
- 1.00000000, 0.58734976, 0.18362641,
- 1.00000000, 0.60724493, 0.22137978,
- 1.00000000, 0.62600248, 0.25591950,
- 1.00000000, 0.64373109, 0.28819679,
- 1.00000000, 0.66052319, 0.31873863,
- 1.00000000, 0.67645822, 0.34786758,
- 1.00000000, 0.69160518, 0.37579588,
- 1.00000000, 0.70602449, 0.40267128,
- 1.00000000, 0.71976951, 0.42860152,
- 1.00000000, 0.73288760, 0.45366838,
- 1.00000000, 0.74542112, 0.47793608,
- 1.00000000, 0.75740814, 0.50145662,
- 1.00000000, 0.76888303, 0.52427322,
- 1.00000000, 0.77987699, 0.54642268,
- 1.00000000, 0.79041843, 0.56793692,
- 1.00000000, 0.80053332, 0.58884417,
- 1.00000000, 0.81024551, 0.60916971,
- 1.00000000, 0.81957693, 0.62893653,
- 1.00000000, 0.82854786, 0.64816570,
- 1.00000000, 0.83717703, 0.66687674,
- 1.00000000, 0.84548188, 0.68508786,
- 1.00000000, 0.85347859, 0.70281616,
- 1.00000000, 0.86118227, 0.72007777,
- 1.00000000, 0.86860704, 0.73688797,
- 1.00000000, 0.87576611, 0.75326132,
- 1.00000000, 0.88267187, 0.76921169,
- 1.00000000, 0.88933596, 0.78475236,
- 1.00000000, 0.89576933, 0.79989606,
- 1.00000000, 0.90198230, 0.81465502,
- 1.00000000, 0.90963069, 0.82838210,
- 1.00000000, 0.91710889, 0.84190889,
- 1.00000000, 0.92441842, 0.85523742,
- 1.00000000, 0.93156127, 0.86836903,
- 1.00000000, 0.93853986, 0.88130458,
- 1.00000000, 0.94535695, 0.89404470,
- 1.00000000, 0.95201559, 0.90658983,
- 1.00000000, 0.95851906, 0.91894041,
- 1.00000000, 0.96487079, 0.93109690,
- 1.00000000, 0.97107439, 0.94305985,
- 1.00000000, 0.97713351, 0.95482993,
- 1.00000000, 0.98305189, 0.96640795,
- 1.00000000, 0.98883326, 0.97779486,
- 1.00000000, 0.99448139, 0.98899179,
- 1.00000000, 1.00000000, 1.00000000,
- 0.98947904, 0.99348723, 1.00000000,
- 0.97940448, 0.98722715, 1.00000000,
- 0.96975025, 0.98120637, 1.00000000,
- 0.96049223, 0.97541240, 1.00000000,
- 0.95160805, 0.96983355, 1.00000000,
- 0.94303638, 0.96443333, 1.00000000,
- 0.93480451, 0.95923080, 1.00000000,
- 0.92689056, 0.95421394, 1.00000000,
- 0.91927697, 0.94937330, 1.00000000,
- 0.91194747, 0.94470005, 1.00000000,
- 0.90488690, 0.94018594, 1.00000000,
- 0.89808115, 0.93582323, 1.00000000,
- 0.89151710, 0.93160469, 1.00000000,
- 0.88518247, 0.92752354, 1.00000000,
- 0.87906581, 0.92357340, 1.00000000,
- 0.87315640, 0.91974827, 1.00000000,
- 0.86744421, 0.91604254, 1.00000000,
- 0.86191983, 0.91245088, 1.00000000,
- 0.85657444, 0.90896831, 1.00000000,
- 0.85139976, 0.90559011, 1.00000000,
- 0.84638799, 0.90231183, 1.00000000,
- 0.84153180, 0.89912926, 1.00000000,
- 0.83682430, 0.89603843, 1.00000000,
- 0.83225897, 0.89303558, 1.00000000,
- 0.82782969, 0.89011714, 1.00000000,
- 0.82353066, 0.88727974, 1.00000000,
- 0.81935641, 0.88452017, 1.00000000,
- 0.81530175, 0.88183541, 1.00000000,
- 0.81136180, 0.87922257, 1.00000000,
- 0.80753191, 0.87667891, 1.00000000,
- 0.80380769, 0.87420182, 1.00000000,
- 0.80018497, 0.87178882, 1.00000000,
- 0.79665980, 0.86943756, 1.00000000,
- 0.79322843, 0.86714579, 1.00000000,
- 0.78988728, 0.86491137, 1.00000000,
- 0.78663296, 0.86273225, 1.00000000,
- 0.78346225, 0.86060650, 1.00000000,
- 0.78037207, 0.85853224, 1.00000000,
- 0.77735950, 0.85650771, 1.00000000,
- 0.77442176, 0.85453121, 1.00000000,
- 0.77155617, 0.85260112, 1.00000000,
- 0.76876022, 0.85071588, 1.00000000,
- 0.76603147, 0.84887402, 1.00000000,
- 0.76336762, 0.84707411, 1.00000000,
- 0.76076645, 0.84531479, 1.00000000,
- 0.75822586, 0.84359476, 1.00000000,
- 0.75574383, 0.84191277, 1.00000000,
- 0.75331843, 0.84026762, 1.00000000,
- 0.75094780, 0.83865816, 1.00000000,
- 0.74863017, 0.83708329, 1.00000000,
- 0.74636386, 0.83554194, 1.00000000,
- 0.74414722, 0.83403311, 1.00000000,
- 0.74197871, 0.83255582, 1.00000000,
- 0.73985682, 0.83110912, 1.00000000,
- 0.73778012, 0.82969211, 1.00000000,
- 0.73574723, 0.82830393, 1.00000000,
- 0.73375683, 0.82694373, 1.00000000,
- 0.73180765, 0.82561071, 1.00000000,
- 0.72989845, 0.82430410, 1.00000000,
- 0.72802807, 0.82302316, 1.00000000,
- 0.72619537, 0.82176715, 1.00000000,
- 0.72439927, 0.82053539, 1.00000000,
- 0.72263872, 0.81932722, 1.00000000,
- 0.72091270, 0.81814197, 1.00000000,
- 0.71922025, 0.81697905, 1.00000000,
- 0.71756043, 0.81583783, 1.00000000,
- 0.71593234, 0.81471775, 1.00000000,
- 0.71433510, 0.81361825, 1.00000000,
- 0.71276788, 0.81253878, 1.00000000,
- 0.71122987, 0.81147883, 1.00000000,
- 0.70972029, 0.81043789, 1.00000000,
- 0.70823838, 0.80941546, 1.00000000,
- 0.70678342, 0.80841109, 1.00000000,
- 0.70535469, 0.80742432, 1.00000000,
- 0.70395153, 0.80645469, 1.00000000,
- 0.70257327, 0.80550180, 1.00000000,
- 0.70121928, 0.80456522, 1.00000000,
- 0.69988894, 0.80364455, 1.00000000,
- 0.69858167, 0.80273941, 1.00000000,
- 0.69729688, 0.80184943, 1.00000000,
- 0.69603402, 0.80097423, 1.00000000,
- 0.69479255, 0.80011347, 1.00000000,
- 0.69357196, 0.79926681, 1.00000000,
- 0.69237173, 0.79843391, 1.00000000,
- 0.69119138, 0.79761446, 1.00000000,
- 0.69003044, 0.79680814, 1.00000000,
- 0.68888844, 0.79601466, 1.00000000,
- 0.68776494, 0.79523371, 1.00000000,
- 0.68665951, 0.79446502, 1.00000000,
- 0.68557173, 0.79370830, 1.00000000,
- 0.68450119, 0.79296330, 1.00000000,
- 0.68344751, 0.79222975, 1.00000000,
- 0.68241029, 0.79150740, 1.00000000,
- 0.68138918, 0.79079600, 1.00000000,
- 0.68038380, 0.79009531, 1.00000000,
- 0.67939381, 0.78940511, 1.00000000,
- 0.67841888, 0.78872517, 1.00000000,
- 0.67745866, 0.78805526, 1.00000000,
- 0.67651284, 0.78739518, 1.00000000,
- 0.67558112, 0.78674472, 1.00000000,
- 0.67466317, 0.78610368, 1.00000000,
- 0.67375872, 0.78547186, 1.00000000,
- 0.67286748, 0.78484907, 1.00000000,
- 0.67198916, 0.78423512, 1.00000000,
- 0.67112350, 0.78362984, 1.00000000,
- 0.67027024, 0.78303305, 1.00000000,
- 0.66942911, 0.78244457, 1.00000000,
- 0.66859988, 0.78186425, 1.00000000,
- 0.66778228, 0.78129191, 1.00000000,
- 0.66697610, 0.78072740, 1.00000000,
- 0.66618110, 0.78017057, 1.00000000,
- 0.66539706, 0.77962127, 1.00000000,
- 0.66462376, 0.77907934, 1.00000000,
- 0.66386098, 0.77854465, 1.00000000,
- 0.66310852, 0.77801705, 1.00000000,
- 0.66236618, 0.77749642, 1.00000000,
- 0.66163375, 0.77698261, 1.00000000,
- 0.66091106, 0.77647551, 1.00000000,
- 0.66019791, 0.77597498, 1.00000000,
- 0.65949412, 0.77548090, 1.00000000,
- 0.65879952, 0.77499315, 1.00000000,
- 0.65811392, 0.77451161, 1.00000000,
- 0.65743716, 0.77403618, 1.00000000,
- 0.65676908, 0.77356673, 1.00000000,
- 0.65610952, 0.77310316, 1.00000000,
- 0.65545831, 0.77264537, 1.00000000,
- 0.65481530, 0.77219324, 1.00000000,
- 0.65418036, 0.77174669, 1.00000000,
- 0.65355332, 0.77130560, 1.00000000,
- 0.65293404, 0.77086988, 1.00000000,
- 0.65232240, 0.77043944, 1.00000000,
- 0.65171824, 0.77001419, 1.00000000,
- 0.65112144, 0.76959404, 1.00000000,
- 0.65053187, 0.76917889, 1.00000000,
- 0.64994941, 0.76876866, 1.00000000,
- 0.64937392, 0.76836326, 1.00000000
- };
-}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b2207f315eb76..7a28f481c990f 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -192,6 +192,9 @@ public boolean updatePhysicalDisplayInfoLocked(
for (int j = 0; j < colorTransforms.size(); j++) {
if (colorTransforms.get(j).getColorTransform() == info.colorTransform) {
existingMode = true;
+ if (i == activeDisplayInfo) {
+ activeColorTransform = colorTransforms.get(j);
+ }
break;
}
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index 239f8cd25cc40..eaeca01f1df6a 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -78,6 +78,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
private static final int RTSP_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
+ // time given for RTSP teardown sequence to complete.
+ private static final int RTSP_TEARDOWN_TIMEOUT = 3;
+
// We repeatedly issue calls to discover peers every so often for a few reasons.
// 1. The initial request may fail and need to retried.
// 2. Discovery will self-abort after any group is initiated, which may not necessarily
@@ -151,6 +154,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
// True if RTSP has connected.
private boolean mRemoteDisplayConnected;
+ // Waiting for displayDisconnected from ERD.
+ private boolean mRemoteDisplayTearingDown;
+
+ // Timed out waiting for RTSP teardown to complete.
+ private boolean mRemoteDisplayRtspTeardownTimedOut;
+
// The information we have most recently told WifiDisplayAdapter about.
private WifiDisplay mAdvertisedDisplay;
private Surface mAdvertisedDisplaySurface;
@@ -363,7 +372,15 @@ private int computeFeatureState() {
}
private void updateScanState() {
- if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
+
+ if (true == mRemoteDisplayTearingDown) {
+ // when rtsp teardown sequence is completed or timed out, this
+ // function will be called again.
+ Slog.i(TAG, "updateScanState no-op as rtsp teardown sequence is in progress");
+ return;
+ }
+
+ if (mScanRequested && mWfdEnabled && (mDesiredDevice == null)) {
if (!mDiscoverPeersInProgress) {
Slog.i(TAG, "Starting Wifi display scan.");
mDiscoverPeersInProgress = true;
@@ -570,7 +587,7 @@ private void updateConnection() {
// Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one.
if ((mRemoteDisplay != null || mExtRemoteDisplay != null) &&
- mConnectedDevice != mDesiredDevice) {
+ mConnectedDevice != mDesiredDevice && false == mRemoteDisplayTearingDown) {
Slog.i(TAG, "Stopped listening for RTSP connection on "
+ mRemoteDisplayInterface
+ " from Wifi display: " + mConnectedDevice.deviceName);
@@ -581,16 +598,25 @@ private void updateConnection() {
ExtendedRemoteDisplayHelper.dispose(mExtRemoteDisplay);
}
- mExtRemoteDisplay = null;
- mRemoteDisplay = null;
- mRemoteDisplayInterface = null;
- mRemoteDisplayConnected = false;
mHandler.removeCallbacks(mRtspTimeout);
+ mRemoteDisplayTearingDown = true;
- mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
- unadvertiseDisplay();
+ // Use extended timeout value for certification, as some tests require user inputs
+ int rtspTimeout = mWifiDisplayCertMode ?
+ RTSP_TIMEOUT_SECONDS_CERT_MODE : RTSP_TIMEOUT_SECONDS;
+
+ Slog.i(TAG, "Starting wait for rtsp teardown sequence for " +
+ rtspTimeout + " secs");
- // continue to next step
+ mHandler.postDelayed(mRtspTimeout, rtspTimeout * 1000);
+
+ return;
+ }
+
+ if (true == mRemoteDisplayTearingDown && false == mRemoteDisplayRtspTeardownTimedOut) {
+ // Need to wait for ERD to notify that p2p connection is no longer needed.
+ Slog.i(TAG, "updateConnection - return as rtsp teardown sequence in progress");
+ return;
}
// Step 2. Before we try to connect to a new device, disconnect from the old one.
@@ -630,6 +656,11 @@ private void next() {
return; // wait for asynchronous callback
}
+ if (true == mRemoteDisplayTearingDown) {
+ Slog.i(TAG, "rtsp teardown sequence in progress");
+ return;
+ }
+
// Step 3. Before we try to connect to a new device, stop trying to connect
// to the old one.
if (mCancelingDevice != null) {
@@ -771,10 +802,11 @@ public void onDisplayConnected(Surface surface,
@Override
public void onDisplayDisconnected() {
+ Slog.i(TAG, "onDisplayDisconnected called");
if (mConnectedDevice == oldDevice) {
Slog.i(TAG, "Closed RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
- mHandler.removeCallbacks(mRtspTimeout);
+ FinishRtspTeardown();
disconnect();
}
}
@@ -907,6 +939,21 @@ public void onGroupInfoAvailable(WifiP2pGroup info) {
}
}
+ private void FinishRtspTeardown()
+ {
+ Slog.i(TAG, "Wait for rtsp teardown sequence completed");
+ mRemoteDisplayTearingDown = false;
+
+ mExtRemoteDisplay = null; // callbacks no longer needed
+ mRemoteDisplay = null;
+ mRemoteDisplayInterface = null;
+ mRemoteDisplayConnected = false;
+ mHandler.removeCallbacks(mRtspTimeout);
+
+ mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
+ unadvertiseDisplay();
+ }
+
private final Runnable mDiscoverPeers = new Runnable() {
@Override
public void run() {
@@ -929,13 +976,31 @@ public void run() {
private final Runnable mRtspTimeout = new Runnable() {
@Override
public void run() {
+ Slog.i(TAG, "mRtspTimeout triggerred");
if (mConnectedDevice != null
- && (mRemoteDisplay != null || mExtRemoteDisplay != null)
- && !mRemoteDisplayConnected) {
- Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
- + RTSP_TIMEOUT_SECONDS + " seconds: "
- + mConnectedDevice.deviceName);
- handleConnectionFailure(true);
+ && (mRemoteDisplay != null || mExtRemoteDisplay != null)) {
+ if (true == mRemoteDisplayTearingDown) {
+ // rtsp teardown sequence timed out
+ Slog.i(TAG, "Timed out waiting for RTSP teardown sequence after "
+ + RTSP_TEARDOWN_TIMEOUT + " seconds: "
+ + mConnectedDevice.deviceName);
+ mRemoteDisplayRtspTeardownTimedOut = true;
+
+ // this should close P2P
+ disconnect();
+
+ FinishRtspTeardown();
+
+ // Ok to resume wifi-scans
+ updateConnection();
+ } else if (!mRemoteDisplayConnected) {
+ Slog.i(TAG, "Timed out waiting for Wifi display RTSP connection after "
+ + RTSP_TIMEOUT_SECONDS + " seconds: "
+ + mConnectedDevice.deviceName);
+ handleConnectionFailure(true);
+ } else {
+ Slog.i(TAG, "Timed out. no-op");
+ }
}
}
};
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 7d1dbe1e54f1d..c986e74de3f87 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -247,6 +247,9 @@ private int getLidStateInternal() {
private void setLidStateInternal(int state) {
synchronized (mLock) {
+ if (mLidState == state) {
+ return;
+ }
mLidState = state;
}
switch (state) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ec7c1c437d92d..e5ab37f0ffe68 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppOpsManager;
@@ -30,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -127,6 +127,7 @@ public void handleMessage(android.os.Message msg) {
private IFingerprintDaemon mDaemon;
private final PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
+ private int mCurrentUserId = UserHandle.USER_NULL;
private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
@Override
@@ -143,12 +144,15 @@ public void run() {
resetFailedAttempts();
}
};
+ private boolean mFingerprintManagerRestrictedToSystemAndOwner;
public FingerprintService(Context context) {
super(context);
mContext = context;
mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
com.android.internal.R.string.config_keyguardComponent)).getPackageName();
+ mFingerprintManagerRestrictedToSystemAndOwner = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_fingerprintRestrictedToSystemAndOwner);
mAppOps = context.getSystemService(AppOpsManager.class);
mPowerManager = mContext.getSystemService(PowerManager.class);
mAlarmManager = mContext.getSystemService(AlarmManager.class);
@@ -337,7 +341,8 @@ void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
return;
}
stopPendingOperations(true);
- mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString());
+ mEnrollClient = new ClientMonitor(token, receiver, mCurrentUserId, groupId, restricted,
+ token.toString());
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.enroll(cryptoToken, groupId, timeout);
@@ -425,7 +430,8 @@ void startAuthentication(IBinder token, long opId, int groupId,
return;
}
stopPendingOperations(true);
- mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
+ mAuthClient = new ClientMonitor(token, receiver, mCurrentUserId, groupId, restricted,
+ opPackageName);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -482,7 +488,8 @@ void startRemove(IBinder token, int fingerId, int userId,
}
stopPendingOperations(true);
- mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
+ mRemoveClient = new ClientMonitor(token, receiver, mCurrentUserId, userId, restricted,
+ token.toString());
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(fingerId, userId);
@@ -582,6 +589,21 @@ private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly)
Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
return false;
}
+ if (mFingerprintManagerRestrictedToSystemAndOwner) {
+ try {
+ ApplicationInfo ai = mContext.getPackageManager()
+ .getApplicationInfo(opPackageName, PackageManager.GET_META_DATA);
+ if (ai != null && ai.isSystemApp() && Binder.getCallingUserHandle().isOwner()) {
+ return true;
+ }
+ Slog.w(TAG, "Rejecting " + opPackageName
+ + "(uid: " + uid + ") ; fingerprint restricted to system apps.");
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.e(TAG, opPackageName + " package not found, not allowing fingerprint access.");
+ return false;
+ }
+ return false;
+ }
return true;
}
@@ -605,15 +627,17 @@ private void notifyLockoutResetMonitors() {
private class ClientMonitor implements IBinder.DeathRecipient {
IBinder token;
IFingerprintServiceReceiver receiver;
- int userId;
+ int userId; // userId of the caller
+ int currentUserId; // current user id when this was created
boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
String owner;
- public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
- boolean restricted, String owner) {
+ public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver,
+ int currentUserId, int userId, boolean restricted, String owner) {
this.token = token;
this.receiver = receiver;
this.userId = userId;
+ this.currentUserId = currentUserId;
this.restricted = restricted;
this.owner = owner; // name of the client that owns this - for debugging
try {
@@ -702,9 +726,9 @@ private boolean sendAuthenticated(int fpId, int groupId) {
Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner
+ ", id=" + fpId + ", gp=" + groupId + ")");
}
- Fingerprint fp = !restricted ?
- new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
- receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
+ Fingerprint fp = !restricted ? new Fingerprint("" /* TODO */, groupId, fpId,
+ mHalDeviceId) : null;
+ receiver.onAuthenticationSucceeded(mHalDeviceId, fp, currentUserId);
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify Authenticated:", e);
@@ -1129,6 +1153,7 @@ private void updateActiveGroup(int userId) {
Slog.e(TAG, "Failed to setActiveGroup():", e);
}
}
+ mCurrentUserId = userId;
}
private void listenForUserSwitches() {
@@ -1139,6 +1164,12 @@ private void listenForUserSwitches() {
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
.sendToTarget();
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
}
@Override
public void onUserSwitchComplete(int newUserId) throws RemoteException {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 16dde26f19cfd..d4762bd8ec189 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -113,9 +113,10 @@ private void stopFlashing() {
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (mModesUpdate || color != mColor || mode != mMode || onMS != mOnMS ||
- offMS != mOffMS) {
+ offMS != mOffMS || mReset) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color));
+ mReset = false;
mColor = color;
mMode = mode;
mOnMS = onMS;
@@ -141,6 +142,7 @@ private void setLightLocked(int color, int mode, int onMS, int offMS, int bright
private boolean mFlashing;
private boolean mModesUpdate;
private boolean mMultipleLeds;
+ private boolean mReset = true;
}
public LightsService(Context context) {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 42b8783a55224..833c3404ac0e2 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -88,6 +88,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
+import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Properties;
@@ -359,6 +360,7 @@ public GpsRequest(ProviderRequest request, WorkSource source) {
private String mC2KServerHost;
private int mC2KServerPort;
private boolean mSuplEsEnabled = false;
+ private HashSet mLastKnownMccMnc;
private final Context mContext;
private final NtpTrustedTime mNtpTime;
@@ -482,18 +484,14 @@ public void onSubscriptionsChanged() {
};
private void subscriptionOrSimChanged(Context context) {
- Log.d(TAG, "received SIM related action: ");
- TelephonyManager phone = (TelephonyManager)
- mContext.getSystemService(Context.TELEPHONY_SERVICE);
- String mccMnc = phone.getSimOperator();
- if (!TextUtils.isEmpty(mccMnc)) {
- Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
- synchronized (mLock) {
+ HashSet mccMnc = getKnownMccMnc(context);
+ Log.d(TAG, "received SIM change, new known MCC/MNC: " + mccMnc);
+ synchronized (mLock) {
+ if (!mccMnc.isEmpty() && !mccMnc.equals(mLastKnownMccMnc)) {
reloadGpsProperties(context, mProperties);
mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
}
- } else {
- Log.d(TAG, "SIM MCC/MNC is still not available");
+ mLastKnownMccMnc = mccMnc;
}
}
@@ -585,6 +583,20 @@ private void reloadGpsProperties(Context context, Properties properties) {
}
}
+ private HashSet getKnownMccMnc(Context context) {
+ final TelephonyManager phone = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ final HashSet mccMnc = new HashSet();
+ final int phoneCnt = phone.getPhoneCount();
+ for (int i = 0;i < phoneCnt; ++i) {
+ String operator = phone.getNetworkOperatorForPhone(i);
+ if (!TextUtils.isEmpty(operator)) {
+ mccMnc.add(operator);
+ }
+ }
+ return mccMnc;
+ }
+
private void loadPropertiesFromResource(Context context,
Properties properties) {
String[] configValues = context.getResources().getStringArray(
@@ -650,6 +662,8 @@ public GpsLocationProvider(Context context, ILocationManager ilocationManager,
// Construct internal handler
mHandler = new ProviderHandler(looper);
+ mLastKnownMccMnc = getKnownMccMnc(mContext);
+
// Load GPS configuration and register listeners in the background:
// some operations, such as opening files and registering broadcast receivers, can take a
// relative long time, so the ctor() is kept to create objects needed by this instance,
@@ -767,6 +781,10 @@ private void handleUpdateNetworkState(int state, NetworkInfo info) {
&& mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
if (mNetworkAvailable) {
String apnName = info.getExtraInfo();
+ // APN wasn't found in the intent, try to get it from the content provider.
+ if (apnName == null) {
+ apnName = getSelectedApn();
+ }
if (apnName == null) {
/* Assign a dummy value in the case of C2K as otherwise we will have a runtime
exception in the following call to native_agps_data_conn_open*/
@@ -1100,7 +1118,7 @@ private void updateRequirements() {
}
if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
- if (mProviderRequest.reportLocation && !mDisableGps) {
+ if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
// update client uids
updateClientUids(mWorkSource);
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index 3585049fab231..6310361573fc4 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -21,8 +21,11 @@
import java.net.HttpURLConnection;
import java.net.URL;
-import libcore.io.Streams;
+import libcore.io.IoUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.Random;
@@ -36,6 +39,7 @@ public class GpsXtraDownloader {
private static final String TAG = "GpsXtraDownloader";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000; // 1MB.
private static final String DEFAULT_USER_AGENT = "Android";
private final String[] mXtraServers;
@@ -121,7 +125,19 @@ protected byte[] doDownload(String url) {
return null;
}
- return Streams.readFully(connection.getInputStream());
+ try (InputStream in = connection.getInputStream()) {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int count;
+ while ((count = in.read(buffer)) != -1) {
+ bytes.write(buffer, 0, count);
+ if (bytes.size() > MAXIMUM_CONTENT_LENGTH_BYTES) {
+ if (DEBUG) Log.d(TAG, "XTRA file too large");
+ return null;
+ }
+ }
+ return bytes.toByteArray();
+ }
} catch (IOException ioe) {
if (DEBUG) Log.d(TAG, "Error downloading gps XTRA: ", ioe);
} finally {
@@ -133,3 +149,4 @@ protected byte[] doDownload(String url) {
}
}
+
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 7028fa6695f66..22f9f72be3de5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -47,6 +47,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -760,6 +761,13 @@ public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ "setup is in progress.");
return;
}
+ if (isGlobalPriorityActive() && uid != Process.SYSTEM_UID) {
+ // Prevent dispatching key event through reflection while the global priority
+ // session is active.
+ Slog.i(TAG, "Only the system can dispatch media key event "
+ + "to the global priority session.");
+ return;
+ }
synchronized (mLock) {
// If we don't have a media button receiver to fall back on
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bf7560ed982fa..4c847a2bcc02d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -45,6 +45,9 @@
import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_ON_DATA;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_ON_WLAN;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_ON_WLAN_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -105,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;
@@ -159,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;
@@ -202,6 +207,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int VERSION_SWITCH_UID = 10;
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
+ @VisibleForTesting
+ public static final int TYPE_NONE = 0;
@VisibleForTesting
public static final int TYPE_WARNING = 0x1;
@VisibleForTesting
@@ -247,6 +254,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
private static final int MSG_SCREEN_ON_CHANGED = 8;
+ private static final int MSG_PROCESS_LOW_POWER_CHANGED = 9;
private final Context mContext;
private final IActivityManager mActivityManager;
@@ -262,6 +270,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private PowerManagerInternal mPowerManagerInternal;
private IDeviceIdleController mDeviceIdleController;
+ private final ComponentName mNotificationComponent;
+ private int mNotificationSequenceNumber;
+
final Object mRulesLock = new Object();
volatile boolean mSystemReady;
@@ -363,6 +374,11 @@ public NetworkPolicyManagerService(Context context, IActivityManager activityMan
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
mAppOps = context.getSystemService(AppOpsManager.class);
+
+ final String notificationComponent = context.getString(
+ R.string.config_networkPolicyNotificationComponent);
+ mNotificationComponent = notificationComponent != null
+ ? ComponentName.unflattenFromString(notificationComponent) : null;
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -437,13 +453,10 @@ public void systemReady() {
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
- public void onLowPowerModeChanged(boolean enabled) {
- synchronized (mRulesLock) {
- if (mRestrictPower != enabled) {
- mRestrictPower = enabled;
- updateRulesForGlobalChangeLocked(true);
- }
- }
+ public void onLowPowerModeChanged(final boolean enabled) {
+ mHandler.removeMessages(MSG_PROCESS_LOW_POWER_CHANGED);
+ Message msg = Message.obtain(mHandler, MSG_PROCESS_LOW_POWER_CHANGED, enabled);
+ mHandler.sendMessage(msg);
}
});
mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
@@ -778,6 +791,11 @@ void updateNotificationsLocked() {
final ArraySet beforeNotifs = new ArraySet(mActiveNotifs);
mActiveNotifs.clear();
+ // increment the sequence number so custom components know
+ // this update is new
+ mNotificationSequenceNumber++;
+ boolean hasNotifications = false;
+
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
@@ -794,6 +812,7 @@ void updateNotificationsLocked() {
final long totalBytes = getTotalBytes(policy.template, start, end);
if (policy.isOverLimit(totalBytes)) {
+ hasNotifications = true;
if (policy.lastLimitSnooze >= start) {
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
@@ -807,10 +826,18 @@ void updateNotificationsLocked() {
if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start
&& policy.limitBytes != LIMIT_DISABLED) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
+ hasNotifications = true;
}
}
}
+ // right now we don't care about restricted background notifications
+ // in the custom notification component, so trigger an update now
+ // if we didn't update anything this pass
+ if (!hasNotifications) {
+ sendNotificationToCustomComponent(null, TYPE_NONE, 0);
+ }
+
// ongoing notification when restricting background data
if (mRestrictBackground) {
enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
@@ -857,6 +884,12 @@ private boolean isTemplateRelevant(NetworkTemplate template) {
* {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
*/
private void notifyOverLimitLocked(NetworkTemplate template) {
+ if (mNotificationComponent != null) {
+ // It is the job of the notification component to handle UI,
+ // so we do nothing here
+ return;
+ }
+
if (!mOverLimitNotified.contains(template)) {
mContext.startActivity(buildNetworkOverLimitIntent(template));
mOverLimitNotified.add(template);
@@ -875,11 +908,55 @@ private String buildNotificationTag(NetworkPolicy policy, int type) {
return TAG + ":" + policy.template.hashCode() + ":" + type;
}
+ private boolean sendNotificationToCustomComponent(
+ NetworkPolicy policy,
+ int type,
+ long totalBytes) {
+ if (mNotificationComponent == null) {
+ return false;
+ }
+
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.setComponent(mNotificationComponent);
+
+ int notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_NONE;
+ switch (type) {
+ case TYPE_WARNING:
+ notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_WARNING;
+ break;
+ case TYPE_LIMIT:
+ notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_REACHED_LIMIT;
+ break;
+ case TYPE_LIMIT_SNOOZED:
+ notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_EXCEEDED_LIMIT;
+ break;
+ }
+
+ intent.setAction(NetworkPolicyManager.ACTION_SHOW_NETWORK_POLICY_NOTIFICATION);
+ intent.putExtra(NetworkPolicyManager.EXTRA_NOTIFICATION_TYPE, notificationType);
+ intent.putExtra(
+ NetworkPolicyManager.EXTRA_NOTIFICATION_SEQUENCE_NUMBER,
+ mNotificationSequenceNumber);
+
+ if (notificationType != NetworkPolicyManager.NOTIFICATION_TYPE_NONE) {
+ intent.putExtra(NetworkPolicyManager.EXTRA_NETWORK_POLICY, policy);
+ intent.putExtra(NetworkPolicyManager.EXTRA_BYTES_USED, totalBytes);
+ }
+
+ mContext.sendBroadcast(intent);
+ return true;
+ }
+
/**
* Show notification for combined {@link NetworkPolicy} and specific type,
* like {@link #TYPE_LIMIT}. Okay to call multiple times.
*/
private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
+ if (sendNotificationToCustomComponent(policy, type, totalBytes)) {
+ return;
+ }
+
final String tag = buildNotificationTag(policy, type);
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setOnlyAlertOnce(true);
@@ -1133,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();
@@ -1739,6 +1820,19 @@ public void snoozeLimit(NetworkTemplate template) {
}
}
+ @Override
+ public void snoozeWarning(NetworkTemplate template) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // TODO: this seems like a race condition? (along with snoozeLimit above)
+ performSnooze(template, TYPE_WARNING);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
void performSnooze(NetworkTemplate template, int type) {
maybeRefreshTrustedTime();
final long currentTime = currentTimeMillis();
@@ -2137,12 +2231,23 @@ void updateRulesForAppIdleLocked() {
uidRules.clear();
// Fully update the app idle firewall chain.
+ final IPackageManager ipm = AppGlobals.getPackageManager();
final List users = mUserManager.getUsers();
for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui);
int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
for (int uid : idleUids) {
if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
+ // quick check: if this uid doesn't have INTERNET permission, it
+ // doesn't have network access anyway, so it is a waste to mess
+ // with it here.
+ try {
+ if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ continue;
+ }
+ } catch (RemoteException e) {
+ }
uidRules.put(uid, FIREWALL_RULE_DENY);
}
}
@@ -2227,11 +2332,13 @@ private static boolean isUidValidForRules(int uid) {
private boolean isUidIdle(int uid) {
final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
- final int userId = UserHandle.getUserId(uid);
- for (String packageName : packages) {
- if (!mUsageStats.isAppIdle(packageName, uid, userId)) {
- return false;
+ if (packages != null) {
+ final int userId = UserHandle.getUserId(uid);
+ for (String packageName : packages) {
+ if (!mUsageStats.isAppIdle(packageName, uid, userId)) {
+ return false;
+ }
}
}
return true;
@@ -2299,6 +2406,14 @@ void updateRulesForUidLocked(int uid) {
uidRules = RULE_REJECT_ALL;
}
+ try {
+ mNetworkManager.restrictAppOnWlan(uid, (uidPolicy & POLICY_REJECT_ON_WLAN) != 0 ||
+ (((uidPolicy & POLICY_REJECT_ON_WLAN_BACKGROUND) != 0) && !uidForeground));
+ mNetworkManager.restrictAppOnData(uid, (uidPolicy & POLICY_REJECT_ON_DATA) != 0);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+
final int oldRules = mUidRules.get(uid);
if (uidRules == RULE_ALLOW_ALL) {
mUidRules.delete(uid);
@@ -2430,6 +2545,16 @@ public boolean handleMessage(Message msg) {
updateScreenOn();
return true;
}
+ case MSG_PROCESS_LOW_POWER_CHANGED: {
+ boolean enabled = (Boolean) msg.obj;
+ synchronized (mRulesLock) {
+ if (mRestrictPower != enabled) {
+ mRestrictPower = enabled;
+ updateRulesForGlobalChangeLocked(true);
+ }
+ }
+ return true;
+ }
default: {
return false;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 15b68c7399459..0176ec435a014 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -491,6 +491,21 @@ public void removeUids(int[] uids) {
}
}
+ /**
+ * Replace data usage history for each matching identity in the template with empty values
+ */
+ public void resetDataUsage(NetworkTemplate template) {
+ final ArrayList knownKeys = Lists.newArrayList();
+ knownKeys.addAll(mStats.keySet());
+
+ for (Key key : knownKeys) {
+ if (templateMatches(template, key.ident)) {
+ mStats.put(key, new NetworkStatsHistory(mBucketDuration, 10));
+ mDirty = true;
+ }
+ }
+ }
+
private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
if (startMillis < mStartMillis) mStartMillis = startMillis;
if (endMillis > mEndMillis) mEndMillis = endMillis;
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 649086575c338..3201981a2966d 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -289,6 +289,31 @@ public void removeUidsLocked(int[] uids) {
}
}
+ /**
+ * Reset data usage for all matching identities in {@link FileRotator} history,
+ */
+ public void resetDataUsageLocked(NetworkTemplate template) {
+ try {
+ // Reset all persisted data to empty values
+ mRotator.rewriteAll(new ResetDataUsageRewriter(mBucketDuration, template));
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem resetting data stats " + e);
+ recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem resetting data stats " + e);
+ recoverFromWtf();
+ }
+
+ // Reset any pending stats
+ mPending.resetDataUsage(template);
+ mSinceBoot.resetDataUsage(template);
+
+ final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+ if (complete != null) {
+ complete.resetDataUsage(template);
+ }
+ }
+
/**
* Rewriter that will combine current {@link NetworkStatsCollection} values
* with anything read from disk, and write combined set to disk. Clears the
@@ -359,6 +384,42 @@ public void write(OutputStream out) throws IOException {
}
}
+ /**
+ * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
+ * identities in input template, replacing it with empty values.
+ */
+ public static class ResetDataUsageRewriter implements FileRotator.Rewriter {
+ private final NetworkStatsCollection mTemp;
+ private NetworkTemplate mTemplate;
+
+ public ResetDataUsageRewriter(long bucketDuration, NetworkTemplate template) {
+ mTemp = new NetworkStatsCollection(bucketDuration);
+ mTemplate = template;
+ }
+
+ @Override
+ public void reset() {
+ mTemp.reset();
+ }
+
+ @Override
+ public void read(InputStream in) throws IOException {
+ mTemp.read(in);
+ mTemp.clearDirty();
+ mTemp.resetDataUsage(mTemplate);
+ }
+
+ @Override
+ public boolean shouldWrite() {
+ return mTemp.isDirty();
+ }
+
+ @Override
+ public void write(OutputStream out) throws IOException {
+ mTemp.write(new DataOutputStream(out));
+ }
+ }
+
public void importLegacyNetworkLocked(File file) throws IOException {
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index acd05f7b3040f..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;
@@ -628,6 +630,26 @@ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate templat
return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
}
+ /**
+ * Reset entire data usage history for all the uids in the template and update global
+ * data stats
+ */
+ @Override
+ public void resetDataUsageHistoryForAllUid(NetworkTemplate template) {
+ mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
+
+ synchronized (mStatsLock) {
+ mWakeLock.acquire();
+ try {
+ resetDataUsageLocked(template);
+ } catch (Exception e) {
+ // ignored; service lives in system_server
+ } finally {
+ mWakeLock.release();
+ }
+ }
+ }
+
@Override
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
@@ -920,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);
@@ -1148,6 +1174,18 @@ private void removeUserLocked(int userId) {
removeUidsLocked(uids);
}
+ /**
+ * Reset data usage history for all uids, uid tags, and global transfer data for the input template
+ */
+ private void resetDataUsageLocked(NetworkTemplate template) {
+ // Perform one last poll before removing
+ performPollLocked(FLAG_PERSIST_ALL);
+
+ mUidRecorder.resetDataUsageLocked(template);
+ mUidTagRecorder.resetDataUsageLocked(template);
+ mXtRecorder.resetDataUsageLocked(template);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
old mode 100755
new mode 100644
index cb1cf47c339c9..422aee2e91138
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -24,7 +24,6 @@
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -58,14 +57,12 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.IRingtonePlayer;
-import android.media.session.MediaController;
-import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -79,6 +76,7 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -103,6 +101,7 @@
import android.util.LruCache;
import android.util.Slog;
import android.util.SparseIntArray;
+import android.util.TimeUtils;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -123,7 +122,10 @@
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.statusbar.StatusBarManagerInternal;
+import cyanogenmod.media.AudioSessionInfo;
+import cyanogenmod.media.CMAudioManager;
import cyanogenmod.providers.CMSettings;
+import cyanogenmod.util.ColorUtils;
import libcore.io.IoUtils;
@@ -248,6 +250,8 @@ public class NotificationManagerService extends SystemService {
private boolean mMultipleNotificationLeds;
private boolean mMultipleLedsEnabledSetting = false;
+ private boolean mAutoGenerateNotificationColor = true;
+
private boolean mScreenOnEnabled = false;
private boolean mScreenOnDefault = false;
@@ -287,6 +291,8 @@ public class NotificationManagerService extends SystemService {
private boolean mNotificationPulseEnabled;
private HashMap mNotificationPulseCustomLedValues;
private Map mPackageNameMappings;
+ private final Map mGeneratedPackageLedColors =
+ new HashMap();
// for checking lockscreen status
private KeyguardManager mKeyguardManager;
@@ -298,6 +304,7 @@ public class NotificationManagerService extends SystemService {
new ArrayMap();
final ArrayList mToastQueue = new ArrayList();
final ArrayMap mSummaryByGroupKey = new ArrayMap<>();
+ final ArrayMap mLastSoundTimestamps = new ArrayMap<>();
final PolicyAccess mPolicyAccess = new PolicyAccess();
// The last key in this list owns the hardware.
@@ -333,6 +340,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;
@@ -702,8 +711,9 @@ public void onNotificationError(int callingUid, int callingPid, String pkg, Stri
"Bad notification posted from package " + pkg
+ ": " + message);
} catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- Binder.restoreCallingIdentity(ident);
}
@Override
@@ -1000,6 +1010,9 @@ void observe() {
resolver.registerContentObserver(CMSettings.Global.getUriFor(
CMSettings.Global.ZEN_DISABLE_DUCKING_DURING_MEDIA_PLAYBACK), false,
this, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO), false,
+ this, UserHandle.USER_ALL);
if (mAdjustableNotificationLedBrightness) {
resolver.registerContentObserver(CMSettings.System.getUriFor(
CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL),
@@ -1024,6 +1037,11 @@ public void update(Uri uri) {
mNotificationPulseEnabled = Settings.System.getIntForUser(resolver,
Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
+ // Automatically pick a color for LED if not set
+ mAutoGenerateNotificationColor = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO,
+ 1, UserHandle.USER_CURRENT) != 0;
+
// LED default color
mDefaultNotificationColor = CMSettings.System.getIntForUser(resolver,
CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR,
@@ -1039,6 +1057,9 @@ public void update(Uri uri) {
CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF,
mDefaultNotificationLedOff, UserHandle.USER_CURRENT);
+ // LED generated notification colors
+ mGeneratedPackageLedColors.clear();
+
// LED custom notification colors
mNotificationPulseCustomLedValues.clear();
if (CMSettings.System.getIntForUser(resolver,
@@ -1076,15 +1097,39 @@ public void update(Uri uri) {
}
}
+ private BroadcastReceiver mMediaSessionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateForActiveSessions();
+ }
+ };
+
+ private void updateForActiveSessions() {
+ CMAudioManager manager = CMAudioManager.getInstance(getContext());
+ List sessions = manager.listAudioSessions(AudioManager.STREAM_MUSIC);
+ mActiveMedia = false;
+ for (AudioSessionInfo sessionInfo : sessions) {
+ if (sessionInfo.getSessionId() > 0) {
+ mActiveMedia = true;
+ break;
+ }
+ }
+ }
+
private void updateDisableDucking() {
if (!mSystemReady) {
return;
}
- final MediaSessionManager mediaSessionManager = (MediaSessionManager) getContext()
- .getSystemService(Context.MEDIA_SESSION_SERVICE);
- mediaSessionManager.removeOnActiveSessionsChangedListener(mSessionListener);
+ try {
+ getContext().unregisterReceiver(mMediaSessionReceiver);
+ } catch (IllegalArgumentException e) {
+ // Never registered
+ }
if (mDisableDuckingWhileMedia) {
- mediaSessionManager.addOnActiveSessionsChangedListener(mSessionListener, null);
+ updateForActiveSessions();
+ IntentFilter intentFilter = new IntentFilter(CMAudioManager
+ .ACTION_AUDIO_SESSIONS_CHANGED);
+ getContext().registerReceiver(mMediaSessionReceiver, intentFilter);
}
}
@@ -1182,6 +1227,8 @@ void onPolicyChanged() {
mDefaultNotificationLedOff = resources.getInteger(
R.integer.config_defaultNotificationLedOff);
+ mMultiColorNotificationLed = deviceLightsCan(NotificationManager.LIGHTS_RGB_NOTIFICATION);
+
mNotificationPulseCustomLedValues = new HashMap();
mPackageNameMappings = new HashMap();
@@ -1202,10 +1249,10 @@ void onPolicyChanged() {
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
- mAdjustableNotificationLedBrightness = resources.getBoolean(
- org.cyanogenmod.platform.internal.R.bool.config_adjustableNotificationLedBrightness);
- mMultipleNotificationLeds = resources.getBoolean(
- org.cyanogenmod.platform.internal.R.bool.config_multipleNotificationLeds);
+ mAdjustableNotificationLedBrightness = deviceLightsCan(
+ NotificationManager.LIGHTS_ADJUSTABLE_NOTIFICATION_BRIGHTNESS);
+ mMultipleNotificationLeds = deviceLightsCan(
+ NotificationManager.LIGHTS_MULTIPLE_LED);
mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
@@ -1218,6 +1265,8 @@ void onPolicyChanged() {
mDisableNotificationEffects = true;
}
mZenModeHelper.initZenMode();
+ mZenModeHelper.readAllowLightsFromSettings();
+ mZenModeHelper.readVibrationModeFromSettings();
mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
mUserProfiles.updateCache(getContext());
@@ -1346,6 +1395,47 @@ private void updateInterruptionFilterLocked() {
scheduleInterruptionFilterChanged(interruptionFilter);
}
+ private int deviceLightsCapabilities() {
+ Resources resources = getContext().getResources();
+ int capabilities = SystemProperties.getInt("sys.lights.capabilities", 0);
+
+ if (capabilities == 0) {
+ int[] deviceCaps = resources.getIntArray(
+ com.android.internal.R.array.config_deviceLightCapabilities);
+ for (int cap : deviceCaps) {
+ capabilities |= 1< getAppActiveNotifications(String
Binder.getCallingUid(), incomingUserId, true, false,
"getAppActiveNotifications", pkg);
- final int N = mNotificationList.size();
- final ArrayList list = new ArrayList(N);
+ final ArrayList list
+ = new ArrayList(mNotificationList.size());
synchronized (mNotificationList) {
+ final int N = mNotificationList.size();
for (int i = 0; i < N; i++) {
final StatusBarNotification sbn = mNotificationList.get(i).sbn;
if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
@@ -1930,6 +2048,7 @@ private void enforceSystemOrSystemUI(String message) {
}
private void enforcePolicyAccess(String pkg, String method) {
+ checkCallerIsSameApp(pkg);
if (!checkPolicyAccess(pkg)) {
Slog.w(TAG, "Notification policy access denied calling " + method);
throw new SecurityException("Notification policy access denied");
@@ -1969,7 +2088,7 @@ public ComponentName getEffectsSuppressor() {
}
@Override
- public boolean matchesCallFilter(Bundle extras) {
+ public boolean[] matchesCallFilter(Bundle extras) {
enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
return mZenModeHelper.matchesCallFilter(
UserHandle.getCallingUserHandle(),
@@ -2082,16 +2201,23 @@ public void setNotificationPolicy(String pkg, Policy policy) {
Binder.restoreCallingIdentity(identity);
}
}
+
+ public boolean deviceLightsCan(int lightCapability) {
+ return ( (deviceLightsCapabilities() & 1< entry: mLastSoundTimestamps.entrySet()) {
+ pw.print(" " + entry.getKey() + " -> ");
+ TimeUtils.formatDuration(entry.getValue(), now, pw);
+ pw.println(" ago");
+ }
}
}
@@ -2603,21 +2737,6 @@ private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
return false;
}
- private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener =
- new MediaSessionManager.OnActiveSessionsChangedListener() {
- @Override
- public void onActiveSessionsChanged(@Nullable List controllers) {
- for (MediaController activeSession : controllers) {
- PlaybackState playbackState = activeSession.getPlaybackState();
- if (playbackState != null && playbackState.getState() == PlaybackState.STATE_PLAYING) {
- mActiveMedia = true;
- return;
- }
- }
- mActiveMedia = false;
- }
- };
-
private void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
@@ -2647,23 +2766,30 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
}
- boolean smsRingtone = getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_sms_ringtone_incall);
- if ((disableEffects == null || (smsRingtone && mInCall))
+
+ boolean readyForBeepOrBuzz = disableEffects == null
&& (!(record.isUpdate
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
- && canInterrupt
+ && !isInSoundTimeoutPeriod(record)
&& mSystemReady
- && mAudioManager != null) {
+ && mAudioManager != null;
+
+ boolean canBeep = readyForBeepOrBuzz && canInterrupt;
+ boolean canBuzz = readyForBeepOrBuzz &&
+ (canInterrupt || (aboveThreshold && mZenModeHelper.allowVibrationForNotifications()));
+ boolean hasValidSound = false;
+
+ if (canBeep || canBuzz) {
if (DBG) Slog.v(TAG, "Interrupting!");
sendAccessibilityEvent(notification, record.sbn.getPackageName());
+ }
- // sound
-
+ // sound
+ if (canBeep) {
// should we use the default notification sound? (indicated either by
// DEFAULT_SOUND or because notification.sound is pointing at
// Settings.System.NOTIFICATION_SOUND)
@@ -2673,7 +2799,6 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
.equals(notification.sound);
Uri soundUri = null;
- boolean hasValidSound = false;
if (useDefaultSound) {
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -2714,15 +2839,17 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
}
}
}
+ }
+
- // vibrate
+ // vibrate
+ if (canBuzz) {
// Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate
// mode, and no other vibration is specified, we fall back to vibration
- final boolean convertSoundToVibration =
- !hasCustomVibrate
+ final boolean convertSoundToVibration = !hasCustomVibrate
&& hasValidSound
&& (mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_VIBRATE);
@@ -2765,8 +2892,9 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
// light
// release the light
boolean wasShowLights = mLights.remove(record.getKey());
- final boolean aboveThresholdWithLight = aboveThreshold || isLedNotificationForcedOn(record);
- if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThresholdWithLight) {
+ final boolean canInterruptWithLight = canInterrupt || isLedNotificationForcedOn(record)
+ || (!canInterrupt && mZenModeHelper.getAllowLights());
+ if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && canInterruptWithLight) {
mLights.add(record.getKey());
updateLightsLocked();
if (mUseAttentionLight) {
@@ -2776,6 +2904,10 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
} else if (wasShowLights) {
updateLightsLocked();
}
+ if (buzz || beep) {
+ mLastSoundTimestamps.put(generateLastSoundTimeoutKey(record),
+ SystemClock.elapsedRealtime());
+ }
if (buzz || beep || blink) {
EventLogTags.writeNotificationAlert(record.getKey(),
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
@@ -2783,6 +2915,24 @@ private void buzzBeepBlinkLocked(NotificationRecord record) {
}
}
+ private boolean isInSoundTimeoutPeriod(NotificationRecord record) {
+ long timeoutMillis = mRankingHelper.getPackageNotificationSoundTimeout(
+ record.sbn.getPackageName(), record.sbn.getUid());
+ if (timeoutMillis == 0) {
+ return false;
+ }
+
+ Long value = mLastSoundTimestamps.get(generateLastSoundTimeoutKey(record));
+ if (value == null) {
+ return false;
+ }
+ return SystemClock.elapsedRealtime() - value < timeoutMillis;
+ }
+
+ private String generateLastSoundTimeoutKey(NotificationRecord record) {
+ return record.sbn.getPackageName() + "|" + record.sbn.getUid();
+ }
+
private static AudioAttributes audioAttributesForNotification(Notification n) {
if (n.audioAttributes != null
&& !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
@@ -3430,7 +3580,7 @@ void updateLightsLocked()
ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn;
ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOff;
} else if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
- ledARGB = mDefaultNotificationColor;
+ ledARGB = generateLedColorForNotification(ledNotification);
ledOnMS = mDefaultNotificationLedOn;
ledOffMS = mDefaultNotificationLedOff;
} else {
@@ -3491,6 +3641,36 @@ private NotificationLedValues getLedValuesForNotification(NotificationRecord led
return mNotificationPulseCustomLedValues.get(mapPackage(packageName));
}
+ 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;
+
+ if (mGeneratedPackageLedColors.containsKey(mapping)) {
+ return mGeneratedPackageLedColors.get(mapping);
+ }
+
+ PackageManager pm = getContext().getPackageManager();
+ Drawable icon;
+ try {
+ icon = pm.getApplicationIcon(mapping);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, e.getMessage(), e);
+ return color;
+ }
+
+ color = ColorUtils.generateAlertColorFromDrawable(icon);
+ mGeneratedPackageLedColors.put(mapping, color);
+
+ return color;
+ }
+
private String mapPackage(String pkg) {
if (!mPackageNameMappings.containsKey(pkg)) {
return pkg;
@@ -3550,6 +3730,10 @@ private static void checkCallerIsSystemOrSameApp(String pkg) {
if (isCallerSystem()) {
return;
}
+ checkCallerIsSameApp(pkg);
+ }
+
+ private static void checkCallerIsSameApp(String pkg) {
final int uid = Binder.getCallingUid();
try {
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
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 a089518c53b8c..233eb0a4bd88d 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -51,6 +51,8 @@ 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 String ATT_SOUND_TIMEOUT = "sound-timeout";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final boolean DEFAULT_PEEKABLE = true;
@@ -143,6 +145,9 @@ 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);
+ long soundTimeout = safeInt(parser, ATT_SOUND_TIMEOUT, 0);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
@@ -172,6 +177,12 @@ 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;
+ }
+ if (soundTimeout != 0) {
+ r.notificationSoundTimeout = soundTimeout;
+ }
}
}
}
@@ -200,8 +211,10 @@ 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) {
- mRecords.remove(i);
+ && r.visibility == DEFAULT_VISIBILITY
+ && r.keyguard == Notification.SHOW_ALL_NOTI_ON_KEYGUARD
+ && r.notificationSoundTimeout == 0) {
+ mRecords.removeAt(i);
}
}
}
@@ -227,6 +240,12 @@ 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 (r.notificationSoundTimeout != 0) {
+ out.attribute(null, ATT_SOUND_TIMEOUT, Long.toString(r.notificationSoundTimeout));
+ }
if (!forBackup) {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
}
@@ -377,6 +396,36 @@ 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 long getPackageNotificationSoundTimeout(String packageName, int uid) {
+ final Record r = mRecords.get(recordKey(packageName, uid));
+ return r != null ? r.notificationSoundTimeout : 0;
+ }
+
+ public void setPackageNotificationSoundTimeout(String packageName, int uid, long timeout) {
+ if (timeout == getPackageNotificationSoundTimeout(packageName, uid)) {
+ return;
+ }
+ getOrCreateRecord(packageName, uid).notificationSoundTimeout = timeout;
+ removeDefaultRecords();
+ }
+
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;
@@ -459,6 +508,8 @@ private static class Record {
int priority = DEFAULT_PRIORITY;
boolean peekable = DEFAULT_PEEKABLE;
int visibility = DEFAULT_VISIBILITY;
+ int keyguard = Notification.SHOW_ALL_NOTI_ON_KEYGUARD;
+ long notificationSoundTimeout = 0;
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 461c3a26ddd7e..54eac0622d536 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -53,6 +53,7 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
import com.android.server.LocalServices;
+import cyanogenmod.providers.CMSettings;
import libcore.io.IoUtils;
@@ -89,6 +90,8 @@ public class ZenModeHelper {
private ZenModeConfig mConfig;
private AudioManagerInternal mAudioManager;
private boolean mEffectsSuppressed;
+ private boolean mAllowLights;
+ private int mVibrationMode;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
@@ -115,10 +118,12 @@ public String toString() {
return TAG;
}
- public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
+ public boolean[] matchesCallFilter(UserHandle userHandle, Bundle extras,
ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
- return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle, extras,
- validator, contactsTimeoutMs, timeoutAffinity);
+ boolean matches = ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig,
+ userHandle, extras, validator, contactsTimeoutMs, timeoutAffinity);
+ boolean matchesForVibration = matches || allowVibrationForCalls();
+ return new boolean[] { matches, matchesForVibration };
}
public boolean isCall(NotificationRecord record) {
@@ -236,6 +241,8 @@ public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mUser="); pw.println(mUser);
dump(pw, prefix, "mConfig", mConfig);
pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
+ pw.print(prefix); pw.print("mAllowLights="); pw.println(mAllowLights);
+ pw.print(prefix); pw.print("mVibrationMode="); pw.println(mVibrationMode);
mFiltering.dump(pw, prefix);
mConditions.dump(pw, prefix);
}
@@ -378,6 +385,8 @@ private boolean evaluateZenMode(String reason, boolean setRingerMode) {
ZenLog.traceSetZenMode(zen, reason);
mZenMode = zen;
updateRingerModeAffectedStreams();
+ readAllowLightsFromSettings();
+ readVibrationModeFromSettings();
setZenModeSetting(mZenMode);
if (setRingerMode) {
applyZenToRingerMode();
@@ -407,6 +416,39 @@ private int computeZenMode(ArraySet automaticRulesOut) {
return zen;
}
+ public boolean getAllowLights() {
+ return mAllowLights;
+ }
+
+ public void readAllowLightsFromSettings() {
+ switch (mZenMode) {
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ case Global.ZEN_MODE_ALARMS:
+ mAllowLights = CMSettings.System.getInt(mContext.getContentResolver(),
+ CMSettings.System.ZEN_ALLOW_LIGHTS, 1) == 1;
+ break;
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ mAllowLights = CMSettings.System.getInt(mContext.getContentResolver(),
+ CMSettings.System.ZEN_PRIORITY_ALLOW_LIGHTS, 1) == 1;
+ break;
+ }
+ }
+
+ public boolean allowVibrationForCalls() {
+ return mVibrationMode > 0;
+ }
+
+ public boolean allowVibrationForNotifications() {
+ return mVibrationMode > 1;
+ }
+
+ public void readVibrationModeFromSettings() {
+ final ContentResolver cr = mContext.getContentResolver();
+ mVibrationMode = mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ ? CMSettings.System.getInt(cr, CMSettings.System.ZEN_PRIORITY_VIBRATION_MODE, 0)
+ : 0;
+ }
+
private void applyRestrictions() {
final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
@@ -415,13 +457,14 @@ private void applyRestrictions() {
applyRestrictions(muteNotifications, USAGE_NOTIFICATION);
// call restrictions
- final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
- || mEffectsSuppressed;
+ final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers;
applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
// alarm restrictions
final boolean muteAlarms = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
applyRestrictions(muteAlarms, USAGE_ALARM);
+
+ readAllowLightsFromSettings();
}
private void applyRestrictions(boolean mute, int usage) {
@@ -692,6 +735,12 @@ public int getRingerModeAffectedStreams(int streams) {
private final class SettingsObserver extends ContentObserver {
private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
+ private final Uri ZEN_ALLOW_LIGHTS = CMSettings.System.getUriFor(
+ CMSettings.System.ZEN_ALLOW_LIGHTS);
+ private final Uri ZEN_PRIORITY_ALLOW_LIGHTS = CMSettings.System.getUriFor(
+ CMSettings.System.ZEN_PRIORITY_ALLOW_LIGHTS);
+ private final Uri ZEN_PRIORITY_VIBRATION_MODE = CMSettings.System.getUriFor(
+ CMSettings.System.ZEN_PRIORITY_VIBRATION_MODE);
public SettingsObserver(Handler handler) {
super(handler);
@@ -700,6 +749,12 @@ public SettingsObserver(Handler handler) {
public void observe() {
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
+ resolver.registerContentObserver(
+ ZEN_ALLOW_LIGHTS, false /*notifyForDescendents*/, this);
+ resolver.registerContentObserver(
+ ZEN_PRIORITY_ALLOW_LIGHTS, false /*notifyForDescendents*/, this);
+ resolver.registerContentObserver(
+ ZEN_PRIORITY_VIBRATION_MODE, false /*notifyForDescendents*/, this);
update(null);
}
@@ -714,6 +769,10 @@ public void update(Uri uri) {
if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
setZenModeSetting(mZenMode);
}
+ } else if (ZEN_ALLOW_LIGHTS.equals(uri) || ZEN_PRIORITY_ALLOW_LIGHTS.equals(uri)) {
+ readAllowLightsFromSettings();
+ } else if (ZEN_PRIORITY_VIBRATION_MODE.equals(uri)) {
+ readVibrationModeFromSettings();
}
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index df023fd8be5d3..29e9fa6cc756c 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -572,6 +572,26 @@ && doesPackageSupportRuntimePermissions(musicPackage)) {
grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId);
}
+ // Android Wear Home
+ if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
+
+ PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackageLPr(
+ homeIntent, userId);
+
+ if (wearHomePackage != null
+ && doesPackageSupportRuntimePermissions(wearHomePackage)) {
+ grantRuntimePermissionsLPw(wearHomePackage, CONTACTS_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissionsLPw(wearHomePackage, PHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissionsLPw(wearHomePackage, MICROPHONE_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissionsLPw(wearHomePackage, LOCATION_PERMISSIONS, false,
+ userId);
+ }
+ }
+
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
@@ -579,7 +599,10 @@ && doesPackageSupportRuntimePermissions(musicPackage)) {
private void grantDefaultPermissionsToDefaultSystemDialerAppLPr(
PackageParser.Package dialerPackage, int userId) {
if (doesPackageSupportRuntimePermissions(dialerPackage)) {
- grantRuntimePermissionsLPw(dialerPackage, PHONE_PERMISSIONS, userId);
+ boolean isPhonePermFixed =
+ mService.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ grantRuntimePermissionsLPw(
+ dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 5f183a2456724..4be7e2585327a 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -129,7 +129,7 @@ public int idmap(String targetApkPath, String overlayApkPath, String cachePath,
}
public int aapt(String themeApkPath, String internalPath, String resTablePath, int uid,
- int pkgId, int minSdkVersion, String commonResourcesPath) {
+ int pkgId, int minSdkVersion, String appResourcesPath, String commonResourcesPath) {
StringBuilder builder = new StringBuilder();
if (TextUtils.isEmpty(commonResourcesPath)) {
@@ -149,6 +149,8 @@ public int aapt(String themeApkPath, String internalPath, String resTablePath, i
builder.append(pkgId);
builder.append(' ');
builder.append(minSdkVersion);
+ builder.append(' ');
+ builder.append(appResourcesPath);
if (!TextUtils.isEmpty(commonResourcesPath)) {
builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/MultiTaskDealer.java b/services/core/java/com/android/server/pm/MultiTaskDealer.java
new file mode 100644
index 0000000000000..9b8d46ecc556d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/MultiTaskDealer.java
@@ -0,0 +1,141 @@
+/*
+* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package com.android.server.pm;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import android.util.Log;
+
+public class MultiTaskDealer {
+
+ public static final String TAG = "MultiTaskDealer";
+ public static final String PACKAGEMANAGER_SCANER = "packagescan";
+ private static final boolean DEBUG_TASK = false;
+
+ private static HashMap> map = new HashMap>();
+
+ public static MultiTaskDealer getDealer(String name) {
+ WeakReference ref = map.get(name);
+ MultiTaskDealer dealer = ref!=null?ref.get():null;
+ return dealer;
+ }
+
+ public static MultiTaskDealer startDealer(String name,int taskCount) {
+ MultiTaskDealer dealer = getDealer(name);
+ if(dealer==null) {
+ dealer = new MultiTaskDealer(name,taskCount);
+ WeakReference ref = new WeakReference(dealer);
+ map.put(name,ref);
+ }
+ return dealer;
+ }
+
+ public void startLock() {
+ mLock.lock();
+ }
+
+ public void endLock() {
+ mLock.unlock();
+ }
+
+ private ThreadPoolExecutor mExecutor;
+ private int mTaskCount = 0;
+ private boolean mNeedNotifyEnd = false;
+ private Object mObjWaitAll = new Object();
+ private ReentrantLock mLock = new ReentrantLock();
+
+ public MultiTaskDealer(String name,int taskCount) {
+ final String taskName = name;
+ ThreadFactory factory = new ThreadFactory()
+ {
+ private final AtomicInteger mCount = new AtomicInteger(1);
+
+ public Thread newThread(final Runnable r) {
+ if (DEBUG_TASK) Log.d(TAG, "create a new thread:" + taskName);
+ return new Thread(r, taskName + "-" + mCount.getAndIncrement());
+ }
+ };
+ mExecutor = new ThreadPoolExecutor(taskCount, taskCount, 5, TimeUnit.SECONDS,
+ new LinkedBlockingQueue(), factory){
+ protected void afterExecute(Runnable r, Throwable t) {
+ if(t!=null) {
+ t.printStackTrace();
+ }
+ MultiTaskDealer.this.TaskCompleteNotify(r);
+ if (DEBUG_TASK) Log.d(TAG, "end task");
+ super.afterExecute(r,t);
+ }
+ protected void beforeExecute(Thread t, Runnable r) {
+ if (DEBUG_TASK) Log.d(TAG, "start task");
+ super.beforeExecute(t,r);
+ }
+ };
+ }
+
+ public void addTask(Runnable task) {
+ synchronized (mObjWaitAll) {
+ mTaskCount+=1;
+ }
+ mExecutor.execute(task);
+ if (DEBUG_TASK) Log.d(TAG, "addTask");
+ }
+
+ private void TaskCompleteNotify(Runnable task) {
+ synchronized (mObjWaitAll) {
+ mTaskCount-=1;
+ if(mTaskCount<=0 && mNeedNotifyEnd) {
+ if (DEBUG_TASK) Log.d(TAG, "complete notify");
+ mObjWaitAll.notify();
+ }
+ }
+ }
+
+ public void waitAll() {
+ if (DEBUG_TASK) Log.d(TAG, "start wait all");
+ synchronized (mObjWaitAll) {
+ if(mTaskCount>0) {
+ mNeedNotifyEnd = true;
+ try {
+ mObjWaitAll.wait();
+ } catch (Exception e) {
+ }
+ mNeedNotifyEnd = false;
+ }
+ if (DEBUG_TASK) Log.d(TAG, "wait finish");
+ return;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f73cb0a1fa641..fa11ff8464dbd 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -57,6 +57,8 @@ final class PackageDexOptimizer {
private final PowerManager.WakeLock mDexoptWakeLock;
private volatile boolean mSystemReady;
+ private Object mDeferredDexOptSync = new Object();
+
PackageDexOptimizer(PackageManagerService packageManagerService) {
this.mPackageManagerService = packageManagerService;
PowerManager powerManager = (PowerManager)packageManagerService.mContext.getSystemService(
@@ -150,7 +152,9 @@ private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructio
// We're deciding to defer a needed dexopt. Don't bother dexopting for other
// paths and instruction sets. We'll deal with them all together when we process
// our list of deferred dexopts.
- addPackageForDeferredDexopt(pkg);
+ synchronized (mDeferredDexOptSync) {
+ addPackageForDeferredDexopt(pkg);
+ }
return DEX_OPT_DEFERRED;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 358b7739b3127..920a8500beadc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2006 The Android Open Source Project
* This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
*
@@ -17,7 +20,6 @@
package com.android.server.pm;
-import static android.Manifest.permission.ACCESS_THEME_MANAGER;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
@@ -92,6 +94,7 @@
import android.Manifest;
+import cyanogenmod.app.CMContextConstants;
import cyanogenmod.app.suggest.AppSuggestManager;
import android.app.ActivityManager;
@@ -156,14 +159,12 @@
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.ManifestDigest;
-import android.content.pm.ThemeUtils;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.res.Resources;
import android.content.res.AssetManager;
import android.content.res.ThemeConfig;
-import android.content.res.ThemeManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Debug;
@@ -222,6 +223,8 @@
import android.view.Display;
import cyanogenmod.providers.CMSettings;
+import cyanogenmod.themes.IThemeService;
+
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -248,12 +251,14 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
+import com.android.server.SystemConfig.AppLink;
import com.android.server.Watchdog;
import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import org.cyanogenmod.internal.util.ThemeUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -303,8 +308,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
/**
* Keep track of all those .apks everywhere.
@@ -334,8 +337,10 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_VERIFY = false;
private static final boolean DEBUG_DEXOPT = false;
+ private static final boolean DEBUG_FILTERS = false;
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_PREBUNDLED_SCAN = false;
+ private static final boolean DEBUG_PROTECTED = false;
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -462,6 +467,9 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final long COMMON_RESOURCE_EXPIRATION = 3*60*1000; // 3 minutes
+ private static final String PROTECTED_APPS_TARGET_VALIDATION_COMPONENT =
+ "com.android.settings/com.android.settings.applications.ProtectedAppsActivity";
+
/**
* The offset in bytes to the beginning of the hashes in an idmap
*/
@@ -613,7 +621,7 @@ public static final class SharedLibraryEntry {
final ArraySet mTransferedPackages = new ArraySet();
// Broadcast actions that are only available to the system.
- final ArraySet mProtectedBroadcasts = new ArraySet();
+ final ArrayMap mProtectedBroadcasts = new ArrayMap<>();
/** List of packages waiting for verification. */
final SparseArray mPendingVerification
@@ -1461,7 +1469,8 @@ void doHandleMessage(Message msg) {
}
String category = null;
if(res.pkg.mIsThemeApk) {
- category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ category = cyanogenmod.content.Intent
+ .CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, null, extras, null, null, updateUsers);
@@ -1487,6 +1496,17 @@ void doHandleMessage(Message msg) {
// if this was a theme, send it off to the theme service for processing
if(res.pkg.mIsThemeApk || res.pkg.mIsLegacyIconPackApk) {
processThemeResourcesInThemeService(res.pkg.packageName);
+ } else if (mOverlays.containsKey(res.pkg.packageName)) {
+
+ // if this was an app and is themed send themes that theme it
+ // for processing
+ ArrayMap themes =
+ mOverlays.get(res.pkg.packageName);
+
+ for (PackageParser.Package themePkg : themes.values()) {
+ processThemeResourcesInThemeService(themePkg.packageName);
+ }
+
}
if (res.removedInfo.args != null) {
// Remove the replaced package's older resources safely now
@@ -1895,7 +1915,9 @@ public PackageManagerService(Context context, Installer installer,
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
- mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
+ mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type")) ||
+ ("userdebug".equals(SystemProperties.get("ro.build.type")) &&
+ SystemProperties.getBoolean("persist.sys.lazy.dexopt", false));
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1956,9 +1978,9 @@ public PackageManagerService(Context context, Installer installer,
mAvailableFeatures = systemConfig.getAvailableFeatures();
mSignatureAllowances = systemConfig.getSignatureAllowances();
- synchronized (mInstallLock) {
+// synchronized (mInstallLock) {
// writer
- synchronized (mPackages) {
+// synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
@@ -2482,8 +2504,8 @@ public PackageManagerService(Context context, Installer installer,
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
- } // synchronized (mPackages)
- } // synchronized (mInstallLock)
+ //} // synchronized (mPackages)
+ //} // synchronized (mInstallLock)
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
@@ -2620,10 +2642,11 @@ private void primeDomainVerificationsLPw(int userId) {
}
SystemConfig systemConfig = SystemConfig.getInstance();
- ArraySet packages = systemConfig.getLinkedApps();
+ ArraySet links = systemConfig.getLinkedApps();
ArraySet domains = new ArraySet();
- for (String packageName : packages) {
+ for (AppLink link : links) {
+ String packageName = link.pkgname;
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
if (!pkg.isSystemApp()) {
@@ -2648,11 +2671,11 @@ private void primeDomainVerificationsLPw(int userId) {
// state w.r.t. the formal app-linkage "no verification attempted" state;
// and then 'always' in the per-user state actually used for intent resolution.
final IntentFilterVerificationInfo ivi;
- ivi = mSettings.createIntentFilterVerificationIfNeededLPw(packageName,
- new ArrayList(domains));
+ ivi = mSettings.createIntentFilterVerificationIfNeededLPw(
+ packageName, new ArrayList(domains));
ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
- mSettings.updateIntentFilterVerificationStatusLPw(packageName,
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, userId);
+ mSettings.updateIntentFilterVerificationStatusLPw(
+ packageName, link.state, userId);
} else {
Slog.w(TAG, "Sysconfig package '" + packageName
+ "' does not handle web links");
@@ -4022,7 +4045,19 @@ public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener liste
@Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
- return mProtectedBroadcasts.contains(actionName);
+ return mProtectedBroadcasts.containsKey(actionName);
+ }
+ }
+
+ @Override
+ public boolean isProtectedBroadcastAllowed(String actionName, int callingUid) {
+ synchronized (mPackages) {
+ if (mProtectedBroadcasts.containsKey(actionName)) {
+ final int result = checkUidPermission(mProtectedBroadcasts.get(actionName),
+ callingUid);
+ return result == PackageManager.PERMISSION_GRANTED;
+ }
+ return false;
}
}
@@ -4695,10 +4730,14 @@ private List getMatchingCrossProfileIntentFilters(Inte
}
private boolean shouldIncludeResolveActivity(Intent intent) {
- synchronized(mPackages) {
- AppSuggestManager suggest = AppSuggestManager.getInstance(mContext);
- return mResolverReplaced && (suggest != null) ? suggest.handles(intent) : false;
+ // Don't call into AppSuggestManager before it comes up later in the SystemServer init!
+ if (!mSystemReady || mOnlyCore) {
+ return false;
}
+
+ AppSuggestManager suggest = AppSuggestManager.getInstance(mContext);
+ return mResolverReplaced && (suggest.getService() != null) ?
+ suggest.handles(intent) : false;
}
@Override
@@ -5791,7 +5830,7 @@ private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
}
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime,
- UserHandle user) {
+ final UserHandle user) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
@@ -5803,8 +5842,8 @@ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime
+ " flags=0x" + Integer.toHexString(parseFlags));
}
- int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
- boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
+ final int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
+ final boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
if (isPrebundled) {
synchronized (mPackages) {
if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Reading prebundled packages for user "
@@ -5813,6 +5852,13 @@ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime
}
}
+ Log.d(TAG, "start scanDirLI:"+dir);
+ // use multi thread to speed up scanning
+ int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
+ Log.d(TAG, "max thread:" + iMultitaskNum);
+ final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
+ MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;
+
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
@@ -5820,43 +5866,64 @@ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime
// Ignore entries which are not packages
continue;
}
- try {
- scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
- scanFlags, currentTime, user);
- if (isPrebundled) {
- final PackageParser.Package pkg;
+
+ final File ref_file = file;
+ final int ref_parseFlags = parseFlags;
+ final int ref_scanFlags = scanFlags;
+ final long ref_currentTime = currentTime;
+
+ Runnable scanTask = new Runnable() {
+ public void run() {
+
try {
- pkg = new PackageParser().parsePackage(file, parseFlags);
- } catch (PackageParserException e) {
- throw PackageManagerException.from(e);
- }
- synchronized (mPackages) {
- if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
- "Marking prebundled packages 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;
- mSettings.markPrebundledPackageInstalledLPr(userInfo.id,
+ scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
+ ref_scanFlags, ref_currentTime, user);
+ if (isPrebundled) {
+ final PackageParser.Package pkg;
+ try {
+ pkg = new PackageParser().parsePackage(ref_file, ref_parseFlags);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+ if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
+ "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);
+ }
+ }
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());
+
+ // Delete invalid userdata apps
+ if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
+ e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
+ logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
+ if (ref_file.isDirectory()) {
+ mInstaller.rmPackageDir(ref_file.getAbsolutePath());
+ } else {
+ ref_file.delete();
+ }
}
}
}
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
+ };
- // Delete invalid userdata apps
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
- e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
- logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
- if (file.isDirectory()) {
- mInstaller.rmPackageDir(file.getAbsolutePath());
- } else {
- file.delete();
- }
- }
- }
+ if (dealer != null)
+ dealer.addTask(scanTask);
+ else
+ scanTask.run();
+ }
+
+ if (dealer != null) {
+ dealer.waitAll();
}
if (isPrebundled) {
@@ -5866,6 +5933,8 @@ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime
mSettings.writePrebundledPackagesLPr(prebundledUserId);
}
}
+
+ Log.d(TAG, "end scanDirLI:"+dir);
}
private static File getSettingsProblemFile() {
@@ -5879,7 +5948,7 @@ static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
- static void logCriticalInfo(int priority, String msg) {
+ static synchronized void logCriticalInfo(int priority, String msg) {
Slog.println(priority, TAG, msg);
EventLogTags.writePmCriticalInfo(msg);
try {
@@ -5969,15 +6038,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,
@@ -6293,9 +6364,8 @@ public void performBootDexOpt() {
if (doTrim) {
if (!isFirstBoot()) {
try {
- ActivityManagerNative.getDefault().showBootMessage(
- mContext.getResources().getString(
- R.string.android_upgrading_fstrim), true);
+ ActivityManagerNative.getDefault().updateBootProgress(
+ IActivityManager.BOOT_STAGE_FSTRIM, null, 0, 0, true);
} catch (RemoteException e) {
}
}
@@ -6422,9 +6492,9 @@ private void performBootDexOpt(PackageParser.Package pkg, int curr, int total) {
Log.i(TAG, "Optimizing app " + curr + " of " + total + ": " + pkg.packageName);
}
try {
- ActivityManagerNative.getDefault().showBootMessage(
- mContext.getResources().getString(R.string.android_upgrading_apk,
- curr, total), true);
+ ActivityManagerNative.getDefault().updateBootProgress(
+ IActivityManager.BOOT_STAGE_PREPARING_APPS,
+ pkg.applicationInfo, curr, total, true);
} catch (RemoteException e) {
}
PackageParser.Package p = pkg;
@@ -7452,6 +7522,25 @@ private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
+ // Get the current theme config. We do this outside the lock
+ // since ActivityManager might be waiting on us already
+ // and a deadlock would result.
+ final boolean isBootScan = (scanFlags & SCAN_BOOTING) != 0;
+ ThemeConfig config = mBootThemeConfig;
+ if (!isBootScan) {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ try {
+ if (am != null) {
+ config = am.getConfiguration().themeConfig;
+ } else {
+ Log.w(TAG, "ActivityManager getDefault() " +
+ "returned null, cannot compile app's theme");
+ }
+ } catch(RemoteException e) {
+ Log.w(TAG, "Failed to get the theme config from ActivityManager");
+ }
+ }
+
// writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
@@ -7793,32 +7882,36 @@ private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int
if (pkg.protectedBroadcasts != null) {
N = pkg.protectedBroadcasts.size();
for (i=0; i themes = mOverlays.get(pkg.packageName);
- for(PackageParser.Package themePkg : themes.values()) {
- if (!isBootScan || (mBootThemeConfig != null &&
- (themePkg.packageName.equals(mBootThemeConfig.getOverlayPkgName()) ||
+
+ if (config != null) {
+ for(PackageParser.Package themePkg : themes.values()) {
+ if (themePkg.packageName.equals(config.getOverlayPkgName()) ||
themePkg.packageName.equals(
- mBootThemeConfig.getOverlayPkgNameForApp(pkg.packageName))))) {
- try {
- compileResourcesAndIdmapIfNeeded(pkg, themePkg);
- } catch (Exception e) {
- // Do not stop a pkg installation just because of one bad theme
- // Also we don't break here because we should try to compile other
- // themes
- Slog.w(TAG, "Unable to compile " + themePkg.packageName
- + " for target " + pkg.packageName, e);
- themePkg.mOverlayTargets.remove(pkg.packageName);
+ config.getOverlayPkgNameForApp(pkg.packageName))) {
+ try {
+ compileResourcesAndIdmapIfNeeded(pkg, themePkg);
+ } catch (Exception e) {
+ // Do not stop a pkg installation just because of one bad theme
+ // Also we don't break here because we should try to compile other
+ // themes
+ Slog.w(TAG, "Unable to compile " + themePkg.packageName
+ + " for target " + pkg.packageName, e);
+ themePkg.mOverlayTargets.remove(pkg.packageName);
+ }
}
}
}
@@ -7852,10 +7945,22 @@ private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int
}
if (failedException != null) {
- Slog.w(TAG, "Unable to process theme " + pkgName + " for " + target,
- failedException);
- // remove target from mOverlayTargets
- iterator.remove();
+ if (failedException instanceof AaptException &&
+ ((AaptException) failedException).isCommon) {
+ Slog.e(TAG, "Unable to process common resources for " + pkgName +
+ ", uninstalling theme.", failedException);
+ uninstallThemeForAllApps(pkg);
+ deletePackageLI(pkg.packageName, null, true, null, null, 0, null,
+ false);
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_THEME_AAPT_ERROR,
+ "Unable to process theme " + pkgName, failedException);
+ } else {
+ Slog.w(TAG, "Unable to process theme " + pkgName + " for " + target,
+ failedException);
+ // remove target from mOverlayTargets
+ iterator.remove();
+ }
}
}
}
@@ -8228,8 +8333,15 @@ private void generateIdmap(String target, PackageParser.Package opkg) throws Idm
}
public class AaptException extends Exception {
+ boolean isCommon;
+
public AaptException(String message) {
+ this(message, false);
+ }
+
+ public AaptException(String message, boolean isCommon) {
super(message);
+ this.isCommon = isCommon;
}
}
@@ -8255,21 +8367,29 @@ private void compileResourcesWithAapt(String target, PackageParser.Package pkg)
String internalPath = APK_PATH_TO_OVERLAY + target + File.separator;
String resPath = ThemeUtils.getTargetCacheDir(target, pkg);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final boolean isCommonResources = COMMON_OVERLAY.equals(target);
int pkgId;
if ("android".equals(target)) {
pkgId = Resources.THEME_FRAMEWORK_PKG_ID;
- } else if (COMMON_OVERLAY.equals(target)) {
+ } else if ("cyanogenmod.platform".equals(target)) {
+ pkgId = Resources.THEME_CM_PKG_ID;
+ } else if (isCommonResources) {
pkgId = Resources.THEME_COMMON_PKG_ID;
} else {
pkgId = Resources.THEME_APP_PKG_ID;
}
- boolean hasCommonResources = (hasCommonResources(pkg) && !COMMON_OVERLAY.equals(target));
+ boolean hasCommonResources = (hasCommonResources(pkg) && !isCommonResources);
+ PackageParser.Package targetPkg = mPackages.get(target);
+ String appPath = targetPkg != null ? targetPkg.baseCodePath :
+ Environment.getRootDirectory() + "/framework/framework-res.apk";
+
if (mInstaller.aapt(pkg.baseCodePath, internalPath, resPath, sharedGid, pkgId,
pkg.applicationInfo.targetSdkVersion,
+ appPath,
hasCommonResources ? ThemeUtils.getTargetCacheDir(COMMON_OVERLAY, pkg)
+ File.separator + "resources.apk" : "") != 0) {
- throw new AaptException("Failed to run aapt");
+ throw new AaptException("Failed to run aapt", isCommonResources);
}
}
@@ -8280,7 +8400,7 @@ private void compileIconsWithAapt(Package pkg) throws Exception {
if (mInstaller.aapt(pkg.baseCodePath, APK_PATH_TO_ICONS, resPath, sharedGid,
Resources.THEME_ICON_PKG_ID,
pkg.applicationInfo.targetSdkVersion,
- "") != 0) {
+ "", "") != 0) {
throw new AaptException("Failed to run aapt");
}
}
@@ -8418,25 +8538,34 @@ private int[] getIdmapHashes(File idmap) throws IOException {
private void setUpCustomResolverActivity(PackageParser.Package pkg) {
synchronized (mPackages) {
- mResolverReplaced = true;
- // Set up information for custom user intent resolution activity.
- mResolveActivity.applicationInfo = pkg.applicationInfo;
- mResolveActivity.name = mCustomResolverComponentName.getClassName();
- mResolveActivity.packageName = pkg.applicationInfo.packageName;
- mResolveActivity.processName = pkg.applicationInfo.packageName;
- mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
- ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
- mResolveActivity.theme = 0;
- mResolveActivity.exported = true;
- mResolveActivity.enabled = true;
- mResolveInfo.activityInfo = mResolveActivity;
- mResolveInfo.priority = 0;
- mResolveInfo.preferredOrder = 0;
- mResolveInfo.match = 0;
- mResolveComponentName = mCustomResolverComponentName;
- Slog.i(TAG, "Replacing default ResolverActivity with custom activity: " +
- mResolveComponentName);
+ for (Activity a : pkg.activities) {
+ if (a.getComponentName().getClassName()
+ .equals(mCustomResolverComponentName.getClassName())) {
+ mResolverReplaced = true;
+ // Set up information for custom user intent resolution activity.
+ mResolveActivity.applicationInfo = pkg.applicationInfo;
+ mResolveActivity.name = mCustomResolverComponentName.getClassName();
+ mResolveActivity.packageName = pkg.applicationInfo.packageName;
+ mResolveActivity.processName = pkg.applicationInfo.packageName;
+ mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
+ ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+ mResolveActivity.theme = a.info.theme;
+ mResolveActivity.exported = true;
+ mResolveActivity.enabled = true;
+ mResolveInfo.activityInfo = mResolveActivity;
+ mResolveInfo.priority = 0;
+ mResolveInfo.preferredOrder = 0;
+ mResolveInfo.match = 0;
+ mResolveComponentName = mCustomResolverComponentName;
+ Slog.i(TAG, "Replacing default ResolverActivity with custom activity: " +
+ mResolveComponentName);
+ break;
+ }
+ }
+ if (mResolveActivity.theme == 0) {
+ mResolveActivity.theme = R.style.Theme_DeviceDefault_Resolver;
+ }
}
}
@@ -9364,12 +9493,15 @@ public List queryIntent(Intent intent, String resolvedType, int fla
mFlags = flags;
List list = super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
- // Remove protected Application components
+ // Remove protected Application components if they're explicitly queried for.
+ // Implicit intent queries will be gated when the returned component is acted upon.
int callingUid = Binder.getCallingUid();
String[] pkgs = getPackagesForUid(callingUid);
List packages = (pkgs != null) ? Arrays.asList(pkgs) : Collections.EMPTY_LIST;
- if (callingUid != Process.SYSTEM_UID &&
- (getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ final boolean isNotSystem = callingUid != Process.SYSTEM_UID &&
+ (getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0;
+
+ if (isNotSystem && intent.getComponent() != null) {
Iterator itr = list.iterator();
while (itr.hasNext()) {
ActivityInfo activityInfo = itr.next().activityInfo;
@@ -9407,6 +9539,255 @@ public List queryIntentForPackage(Intent intent, String resolvedTyp
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
}
+ /**
+ * Finds a privileged activity that matches the specified activity names.
+ */
+ private PackageParser.Activity findMatchingActivity(
+ List activityList, ActivityInfo activityInfo) {
+ for (PackageParser.Activity sysActivity : activityList) {
+ if (sysActivity.info.name.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity != null) {
+ if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+ return sysActivity;
+ }
+ if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+ return sysActivity;
+ }
+ }
+ }
+ return null;
+ }
+
+ public class IterGenerator {
+ public Iterator generate(ActivityIntentInfo info) {
+ return null;
+ }
+ }
+
+ public class ActionIterGenerator extends IterGenerator {
+ @Override
+ public Iterator generate(ActivityIntentInfo info) {
+ return info.actionsIterator();
+ }
+ }
+
+ public class CategoriesIterGenerator extends IterGenerator {
+ @Override
+ public Iterator generate(ActivityIntentInfo info) {
+ return info.categoriesIterator();
+ }
+ }
+
+ public class SchemesIterGenerator extends IterGenerator {
+ @Override
+ public Iterator generate(ActivityIntentInfo info) {
+ return info.schemesIterator();
+ }
+ }
+
+ public class AuthoritiesIterGenerator extends IterGenerator {
+ @Override
+ public Iterator generate(ActivityIntentInfo info) {
+ return info.authoritiesIterator();
+ }
+ }
+
+ /**
+ * WARNING for performance reasons, the passed in intentList WILL BE
+ * MODIFIED. Do not pass in a list that should not be changed.
+ */
+ private void getIntentListSubset(List intentList,
+ IterGenerator generator, Iterator searchIterator) {
+ // loop through the set of actions; every one must be found in the intent filter
+ while (searchIterator.hasNext()) {
+ // we must have at least one filter in the list to consider a match
+ if (intentList.size() == 0) {
+ break;
+ }
+
+ final T searchAction = searchIterator.next();
+
+ // loop through the set of intent filters
+ final Iterator intentIter = intentList.iterator();
+ while (intentIter.hasNext()) {
+ final ActivityIntentInfo intentInfo = intentIter.next();
+ boolean selectionFound = false;
+
+ // loop through the intent filter's selection criteria; at least one
+ // of them must match the searched criteria
+ final Iterator intentSelectionIter = generator.generate(intentInfo);
+ while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
+ final T intentSelection = intentSelectionIter.next();
+ if (intentSelection != null && intentSelection.equals(searchAction)) {
+ selectionFound = true;
+ break;
+ }
+ }
+
+ // the selection criteria wasn't found in this filter's set; this filter
+ // is not a potential match
+ if (!selectionFound) {
+ intentIter.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Adjusts the priority of the given intent filter according to policy.
+ *
+ *
+ * - The priority for unbundled updates to system applications is capped to the
+ * priority defined on the system partition
+ *
+ */
+ private void adjustPriority(
+ List systemActivities, ActivityIntentInfo intent) {
+ // nothing to do; priority is fine as-is
+ if (intent.getPriority() <= 0) {
+ return;
+ }
+
+ final ActivityInfo activityInfo = intent.activity.info;
+ final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+
+ final boolean systemApp = applicationInfo.isSystemApp();
+ if (!systemApp) {
+ // non-system applications can never define a priority >0
+ Slog.w(TAG, "Non-system app; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ intent.setPriority(0);
+ return;
+ }
+
+ if (systemActivities == null) {
+ // the system package is not disabled; we're parsing the system partition
+ // apps on the system image get whatever priority they request
+ return;
+ }
+
+ // system app unbundled update ... try to find the same activity
+ final PackageParser.Activity foundActivity =
+ findMatchingActivity(systemActivities, activityInfo);
+ if (foundActivity == null) {
+ // this is a new activity; it cannot obtain >0 priority
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "New activity; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+
+ // found activity, now check for filter equivalence
+
+ // a shallow copy is enough; we modify the list, not its contents
+ final List intentListCopy =
+ new ArrayList<>(foundActivity.intents);
+ final List foundFilters = findFilters(intent);
+
+ // find matching action subsets
+ final Iterator actionsIterator = intent.actionsIterator();
+ if (actionsIterator != null) {
+ getIntentListSubset(
+ intentListCopy, new ActionIterGenerator(), actionsIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched action; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching category subsets
+ final Iterator categoriesIterator = intent.categoriesIterator();
+ if (categoriesIterator != null) {
+ getIntentListSubset(intentListCopy, new CategoriesIterGenerator(),
+ categoriesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched category; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching schemes subsets
+ final Iterator schemesIterator = intent.schemesIterator();
+ if (schemesIterator != null) {
+ getIntentListSubset(intentListCopy, new SchemesIterGenerator(),
+ schemesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // find matching authorities subsets
+ final Iterator
+ authoritiesIterator = intent.authoritiesIterator();
+ if (authoritiesIterator != null) {
+ getIntentListSubset(intentListCopy,
+ new AuthoritiesIterGenerator(),
+ authoritiesIterator);
+ if (intentListCopy.size() == 0) {
+ // no more intents to match; we're not equivalent
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Mismatched authority; cap priority to 0;"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(0);
+ return;
+ }
+ }
+
+ // we found matching filter(s); app gets the max priority of all intents
+ int cappedPriority = 0;
+ for (int i = intentListCopy.size() - 1; i >= 0; --i) {
+ cappedPriority = Math.max(cappedPriority, intentListCopy.get(i).getPriority());
+ }
+ if (intent.getPriority() > cappedPriority) {
+ if (DEBUG_FILTERS) {
+ Slog.i(TAG, "Found matching filter(s);"
+ + " cap priority to " + cappedPriority + ";"
+ + " package: " + applicationInfo.packageName
+ + " activity: " + intent.activity.className
+ + " origPrio: " + intent.getPriority());
+ }
+ intent.setPriority(cappedPriority);
+ return;
+ }
+ // all this for nothing; the requested priority was <= what was on the system
+ }
+
public final void addActivity(PackageParser.Activity a, String type) {
final boolean systemApp = a.info.applicationInfo.isSystemApp();
mActivities.put(a.getComponentName(), a);
@@ -9419,10 +9800,12 @@ public final void addActivity(PackageParser.Activity a, String type) {
final int NI = a.intents.size();
for (int j=0; j 0 && "activity".equals(type)) {
- intent.setPriority(0);
- Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
- + a.className + " with priority > 0, forcing to 0");
+ if ("activity".equals(type)) {
+ final PackageSetting ps =
+ mSettings.getDisabledSystemPkgLPr(intent.activity.info.packageName);
+ final List systemActivities =
+ ps != null && ps.pkg != null ? ps.pkg.activities : null;
+ adjustPriority(systemActivities, intent);
}
if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
@@ -9576,18 +9959,6 @@ protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int
out.println();
}
-// List filterEnabled(List resolveInfoList) {
-// final Iterator i = resolveInfoList.iterator();
-// final List retList = Lists.newArrayList();
-// while (i.hasNext()) {
-// final ResolveInfo resolveInfo = i.next();
-// if (isEnabledLP(resolveInfo.activityInfo)) {
-// retList.add(resolveInfo);
-// }
-// }
-// return retList;
-// }
-
// Keys are String (activity class name), values are Activity.
private final ArrayMap mActivities
= new ArrayMap();
@@ -10155,10 +10526,10 @@ void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
void startCleaningPackages() {
// reader
+ if (!isExternalMediaAvailable()) {
+ return;
+ }
synchronized (mPackages) {
- if (!isExternalMediaAvailable()) {
- return;
- }
if (mSettings.mPackagesToBeCleaned.isEmpty()) {
return;
}
@@ -10266,8 +10637,8 @@ private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetti
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userId, pkgSetting.appId));
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, null,
- packageName, extras, null, null, new int[] {userId});
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+ null, extras, null, null, new int[] {userId});
try {
IActivityManager am = ActivityManagerNative.getDefault();
final boolean isSystem =
@@ -11134,7 +11505,7 @@ class InstallParams extends HandlerParams {
final IPackageInstallObserver2 observer;
int installFlags;
final String installerPackageName;
- final String volumeUuid;
+ String volumeUuid;
final VerificationParams verificationParams;
private InstallArgs mArgs;
private int mRet;
@@ -11339,6 +11710,28 @@ public void handleStartCopy() throws RemoteException {
}
}
+ // Check whether we're replacing an existing package that's
+ // installed on adopted storage. If yes, override the new
+ // package location to match.
+ if (move == null && (installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(pkgLite.packageName);
+ if (pkg != null && isExternalAdopted(pkg)) {
+ // Check whether anything will actually change
+ // so that we log only when a fixup was needed
+ if (!((installFlags & PackageManager.INSTALL_INTERNAL) != 0
+ && (installFlags & PackageManager.INSTALL_EXTERNAL) == 0
+ && Objects.equals(volumeUuid, pkg.volumeUuid))) {
+ installFlags |= PackageManager.INSTALL_INTERNAL;
+ installFlags &= ~PackageManager.INSTALL_EXTERNAL;
+ volumeUuid = pkg.volumeUuid;
+ Slog.w(TAG, "Replacing package on adopted storage, updating "
+ +"new package destination to volumeUuid "+volumeUuid);
+ }
+ }
+ }
+ }
+
final InstallArgs args = createInstallArgs(this);
mArgs = args;
@@ -11647,8 +12040,6 @@ int doPreCopy() {
* Called after the source arguments are copied. This is used mostly for
* MoveParams when it needs to read the source file to put it in the
* destination.
- *
- * @return
*/
int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED;
@@ -13292,6 +13683,14 @@ private static boolean isExternal(ApplicationInfo info) {
return (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
+ // Package is assumed to be on adopted storage if:
+ // FLAG_EXTERNAL_STORAGE is set
+ // volumeUuid is neither private internal (null) nor primary physical
+ private static boolean isExternalAdopted(PackageParser.Package pkg) {
+ return isExternal(pkg) && !TextUtils.isEmpty(pkg.volumeUuid)
+ && !Objects.equals(pkg.volumeUuid, StorageManager.UUID_PRIMARY_PHYSICAL);
+ }
+
private static boolean isSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -13522,7 +13921,8 @@ private int deletePackageX(String packageName, int userId, int flags) {
String category = null;
if (info.isThemeApk) {
- category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ category = cyanogenmod.content.Intent
+ .CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, category,
@@ -13567,7 +13967,8 @@ void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllU
if (removedPackage != null) {
String category = null;
if (isThemeApk) {
- category = Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
+ category = cyanogenmod.content.Intent
+ .CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE;
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, category,
extras, null, null, removedUsers);
@@ -15370,6 +15771,9 @@ public void systemReady() {
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
synchronized (mPackages) {
+ // process applied themes so their resources are up to date and ready use
+ processAppliedThemes();
+
// Verify that all of the preferred activity components actually
// exist. It is possible for applications to be updated and at
// that point remove a previously declared activity component that
@@ -17179,6 +17583,70 @@ public void setComponentProtectedSetting(ComponentName componentName, boolean ne
}
}
+ @Override
+ 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
+ + " and callinguid " + callingUid);
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "set protected");
+
+ //Allow managers full access
+ List protectedComponentManagers =
+ CMSettings.Secure.getDelimitedStringAsList(mContext.getContentResolver(),
+ CMSettings.Secure.PROTECTED_COMPONENT_MANAGERS, "|");
+ if (protectedComponentManagers.contains(callingPackage)) {
+ if (DEBUG_PROTECTED) Log.d(TAG, "Calling package is a protected manager, allow");
+ return false;
+ }
+
+ String packageName = componentName.getPackageName();
+ String className = componentName.getClassName();
+
+ //If this component is launched from the same package, allow it.
+ if (TextUtils.equals(packageName, callingPackage)) {
+ if (DEBUG_PROTECTED) Log.d(TAG, "Calling package is same as target, allow");
+ return false;
+ }
+
+ //If this component is launched from a validation component, allow it.
+ if (TextUtils.equals(PROTECTED_APPS_TARGET_VALIDATION_COMPONENT,
+ 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) {
+ int packageUid = getPackageUid(protectedComponentManager, userId);
+ if (packageUid != -1 && callingUid == packageUid) {
+ 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;
+ }
+
+ PackageSetting pkgSetting;
+ ArraySet components;
+
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+
+ if (pkgSetting == null || className == null) {
+ return false;
+ }
+ // Get all the protected components
+ components = pkgSetting.getProtectedComponents(userId);
+ if (DEBUG_PROTECTED) Log.d(TAG, "Got " + components.size() + " protected components");
+ return components.size() > 0;
+ }
+ }
+
@Override
public boolean isStorageLow() {
final long token = Binder.clearCallingIdentity();
@@ -17632,8 +18100,11 @@ public ComposedIconInfo getComposedIconInfo() {
@Override
public int processThemeResources(String themePkgName) {
mContext.enforceCallingOrSelfPermission(
- Manifest.permission.ACCESS_THEME_MANAGER, null);
- PackageParser.Package pkg = mPackages.get(themePkgName);
+ cyanogenmod.platform.Manifest.permission.ACCESS_THEME_MANAGER, null);
+ PackageParser.Package pkg;
+ synchronized (mPackages) {
+ pkg = mPackages.get(themePkgName);
+ }
if (pkg == null) {
Log.w(TAG, "Unable to get pkg for processing " + themePkgName);
return 0;
@@ -17654,11 +18125,15 @@ public int processThemeResources(String themePkgName) {
// Generate Idmaps and res tables if pkg is a theme
Iterator iterator = pkg.mOverlayTargets.iterator();
- while(iterator.hasNext()) {
+ while (iterator.hasNext()) {
String target = iterator.next();
Exception failedException = null;
+ PackageParser.Package targetPkg;
+ synchronized (mPackages) {
+ targetPkg = mPackages.get(target);
+ }
try {
- compileResourcesAndIdmapIfNeeded(mPackages.get(target), pkg);
+ compileResourcesAndIdmapIfNeeded(targetPkg, pkg);
} catch (IdmapException e) {
failedException = e;
} catch (AaptException e) {
@@ -17668,10 +18143,20 @@ public int processThemeResources(String themePkgName) {
}
if (failedException != null) {
- Slog.w(TAG, "Unable to process theme " + pkg.packageName + " for " + target,
- failedException);
- // remove target from mOverlayTargets
- iterator.remove();
+ if (failedException instanceof AaptException &&
+ ((AaptException) failedException).isCommon) {
+ Slog.e(TAG, "Unable to process common resources for " + pkg.packageName +
+ ", uninstalling theme.", failedException);
+ uninstallThemeForAllApps(pkg);
+ deletePackageX(pkg.packageName, getCallingUid(),
+ PackageManager.DELETE_ALL_USERS);
+ return PackageManager.INSTALL_FAILED_THEME_AAPT_ERROR;
+ } else {
+ Slog.w(TAG, "Unable to process theme " + pkg.packageName + " for " + target,
+ failedException);
+ // remove target from mOverlayTargets
+ iterator.remove();
+ }
}
}
@@ -17679,11 +18164,57 @@ public int processThemeResources(String themePkgName) {
}
private void processThemeResourcesInThemeService(String pkgName) {
- ThemeManager tm =
- (ThemeManager) mContext.getSystemService(Context.THEME_SERVICE);
- if (tm != null) {
- tm.processThemeResources(pkgName);
+ IThemeService ts = IThemeService.Stub.asInterface(ServiceManager.getService(
+ CMContextConstants.CM_THEME_SERVICE));
+ if (ts == null) {
+ Slog.e(TAG, "Theme service not available");
+ return;
}
+ try {
+ ts.processThemeResources(pkgName);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
+
+ /**
+ * Makes sure resources and idmaps for themes that are applied are up to date. This should only
+ * impact boots when something on /system has changed.
+ */
+ private void processAppliedThemes() {
+ ThemeConfig themeConfig = ThemeConfig.getBootTheme(mContext.getContentResolver());
+ if (themeConfig == null) return;
+
+ // gather up all the themes applied and then process them
+ Set themesToProcess = new ArraySet();
+ // process theme set for icons
+ if (themeConfig.getIconPackPkgName() != null) {
+ themesToProcess.add(themeConfig.getIconPackPkgName());
+ }
+ // process theme set for non-app specific overlays
+ if (themeConfig.getOverlayPkgName() != null) {
+ themesToProcess.add(themeConfig.getOverlayPkgName());
+ }
+ // process theme set for status bar
+ if (themeConfig.getOverlayForStatusBar() != null) {
+ themesToProcess.add(themeConfig.getOverlayForStatusBar());
+ }
+ // process theme set for navigation bar
+ if (themeConfig.getOverlayForNavBar() != null) {
+ themesToProcess.add(themeConfig.getOverlayForNavBar());
+ }
+ // process themes set for specific apps
+ Map appThemesMap = themeConfig.getAppThemes();
+ for (String themePkgName : appThemesMap.keySet()) {
+ themesToProcess.add(themePkgName);
+ }
+
+ // now start the processing
+ for (String themePkgName : themesToProcess) {
+ processThemeResources(themePkgName);
+ }
+
+ updateIconMapping(themeConfig.getIconPackPkgName());
}
private void createAndSetCustomResources() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7b951060659f2..38478c2e6e270 100755
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -338,7 +338,7 @@ public void forceCurrent() {
// Packages that have been uninstalled and still need their external
// storage data deleted.
final ArrayList mPackagesToBeCleaned = new ArrayList();
-
+
// Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original
// names. The packages appear everwhere else under their original
@@ -2459,11 +2459,16 @@ void readPrebundledPackagesLPr(int userId) {
private void readPrebundledPackagesForUserFromFileLPr(int userId, File file) {
BufferedReader reader = null;
try {
+ HashSet ppkg = mPrebundledPackages.get(userId);
+ if (ppkg == null) {
+ Slog.e(PackageManagerService.TAG, "Unable to get packages for user " + userId);
+ return;
+ }
reader = new BufferedReader(new FileReader(file));
String packageName = reader.readLine();
while (packageName != null) {
if (!TextUtils.isEmpty(packageName)) {
- mPrebundledPackages.get(userId).add(packageName);
+ ppkg.add(packageName);
}
packageName = reader.readLine();
}
@@ -2519,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)) {
@@ -2552,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");
@@ -3751,7 +3787,7 @@ private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException,
}
String tagName = parser.getName();
- // Legacy
+ // Legacy
if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
readDisabledComponentsLPw(packageSetting, parser, 0);
} else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
@@ -4029,7 +4065,7 @@ public PackageSetting getDisabledSystemPkgLPr(String name) {
private String compToString(ArraySet cmp) {
return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
}
-
+
boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
return true;
diff --git a/services/core/java/com/android/server/pm/UserContentObserver.java b/services/core/java/com/android/server/pm/UserContentObserver.java
new file mode 100644
index 0000000000000..6145c3ba370da
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UserContentObserver.java
@@ -0,0 +1,92 @@
+/*
+ * 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.server.pm;
+
+import android.app.ActivityManagerNative;
+import android.app.IUserSwitchObserver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Simple extension of ContentObserver that also listens for user switch events to call update
+ */
+public abstract class UserContentObserver extends ContentObserver {
+ private static final String TAG = "UserContentObserver";
+
+ private Runnable mUpdateRunnable;
+
+ private IUserSwitchObserver mUserSwitchObserver = new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ }
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ mHandler.post(mUpdateRunnable);
+ }
+ @Override
+ public void onForegroundProfileSwitch(int newProfileId) {
+ }
+ };
+
+ private Handler mHandler;
+
+ /**
+ * Content observer that tracks user switches
+ * to allow clients to re-load settings for current user
+ */
+ public UserContentObserver(Handler handler) {
+ super(handler);
+ mHandler = handler;
+ mUpdateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ };
+ }
+
+ protected void observe() {
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register user switch observer!", e);
+ }
+ }
+
+ protected void unobserve() {
+ try {
+ mHandler.removeCallbacks(mUpdateRunnable);
+ ActivityManagerNative.getDefault().unregisterUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to unregister user switch observer!", e);
+ }
+ }
+
+ /**
+ * Called to notify of registered uri changes and user switches.
+ * Always invoked on the handler passed in at construction
+ */
+ protected abstract void update();
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 06c3682fa988a..583d7649a292d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -125,6 +125,11 @@ public class UserManagerService extends IUserManager.Stub {
private static final String RESTRICTIONS_FILE_PREFIX = "res_";
private static final String XML_SUFFIX = ".xml";
+ private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
+ UserInfo.FLAG_MANAGED_PROFILE
+ | UserInfo.FLAG_RESTRICTED
+ | UserInfo.FLAG_GUEST;
+
private static final int MIN_USER_ID = 10;
private static final int USER_VERSION = 5;
@@ -262,11 +267,22 @@ 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
public List getUsers(boolean excludeDying) {
- checkManageUsersPermission("query users");
+ checkManageOrCreateUsersPermission("query users");
synchronized (mPackagesLock) {
ArrayList users = new ArrayList(mUsers.size());
for (int i = 0; i < mUsers.size(); i++) {
@@ -285,7 +301,7 @@ public List getUsers(boolean excludeDying) {
@Override
public List getProfiles(int userId, boolean enabledOnly) {
if (userId != UserHandle.getCallingUserId()) {
- checkManageUsersPermission("getting profiles related to user " + userId);
+ checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -377,7 +393,7 @@ public void setUserEnabled(int userId) {
@Override
public UserInfo getUserInfo(int userId) {
- checkManageUsersPermission("query user");
+ checkManageOrCreateUsersPermission("query user");
synchronized (mPackagesLock) {
return getUserInfoLocked(userId);
}
@@ -509,6 +525,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);
}
}
@@ -664,6 +681,71 @@ private static final void checkManageUsersPermission(String message) {
}
}
+ /**
+ * Enforces that only the system UID or root's UID or apps that have the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}
+ * can make certain calls to the UserManager.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ * @see #hasManageOrCreateUsersPermission()
+ */
+ private static final void checkManageOrCreateUsersPermission(String message) {
+ if (!hasManageOrCreateUsersPermission()) {
+ throw new SecurityException(
+ "You either need MANAGE_USERS or CREATE_USERS permission to: " + message);
+ }
+ }
+
+ /**
+ * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
+ * to create user/profiles other than what is allowed for
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} permission, then it will only
+ * allow callers with {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} permission.
+ */
+ private static final void checkManageOrCreateUsersPermission(int creationFlags) {
+ if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
+ if (!hasManageOrCreateUsersPermission()) {
+ throw new SecurityException("You either need MANAGE_USERS or CREATE_USERS "
+ + "permission to create an user with flags: " + creationFlags);
+ }
+ } else if (!hasManageUsersPermission()) {
+ throw new SecurityException("You need MANAGE_USERS permission to create an user "
+ + " with flags: " + creationFlags);
+ }
+ }
+
+ /**
+ * @return whether the calling UID is system UID or root's UID or the calling app has the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
+ */
+ private static final boolean hasManageUsersPermission() {
+ final int callingUid = Binder.getCallingUid();
+ return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || callingUid == Process.ROOT_UID
+ || ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * @return whether the calling UID is system UID or root's UID or the calling app has the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+ */
+ private static final boolean hasManageOrCreateUsersPermission() {
+ final int callingUid = Binder.getCallingUid();
+ return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || callingUid == Process.ROOT_UID
+ || ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+ || ActivityManager.checkComponentPermission(
+ android.Manifest.permission.CREATE_USERS,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ }
+
private static void checkSystemOrRoot(String message) {
final int uid = Binder.getCallingUid();
if (uid != Process.SYSTEM_UID && uid != 0) {
@@ -1215,7 +1297,7 @@ private void cleanAppRestrictionsForPackage(String pkg, int userId) {
@Override
public UserInfo createProfileForUser(String name, int flags, int userId) {
- checkManageUsersPermission("Only the system can create users");
+ checkManageOrCreateUsersPermission(flags);
if (userId != UserHandle.USER_OWNER) {
Slog.w(LOG_TAG, "Only user owner can have profiles");
return null;
@@ -1225,7 +1307,7 @@ public UserInfo createProfileForUser(String name, int flags, int userId) {
@Override
public UserInfo createUser(String name, int flags) {
- checkManageUsersPermission("Only the system can create users");
+ checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, UserHandle.USER_NULL);
}
@@ -1390,7 +1472,7 @@ public boolean markGuestForDeletion(int userHandle) {
* @param userHandle the user's id
*/
public boolean removeUser(int userHandle) {
- checkManageUsersPermission("Only the system can remove users");
+ checkManageOrCreateUsersPermission("Only the system can remove users");
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
UserManager.DISALLOW_REMOVE_USER, false)) {
Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index fef1e57504cd4..e6ec6a67fe3af 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -72,6 +72,9 @@ public class BurnInProtectionHelper implements DisplayManager.DisplayListener,
/* 1 means increasing, -1 means decreasing */
private int mYOffsetDirection = 1;
+ private int mAppliedBurnInXOffset = 0;
+ private int mAppliedBurnInYOffset = 0;
+
private final AlarmManager mAlarmManager;
private final PendingIntent mBurnInProtectionIntent;
private final DisplayManagerInternal mDisplayManagerInternal;
@@ -139,6 +142,8 @@ private void updateBurnInProtection() {
mFirstUpdate = false;
} else {
adjustOffsets();
+ mAppliedBurnInXOffset = mLastBurnInXOffset;
+ mAppliedBurnInYOffset = mLastBurnInYOffset;
mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
mLastBurnInXOffset, mLastBurnInYOffset);
}
@@ -258,6 +263,8 @@ public void onAnimationStart(Animator animator) {
@Override
public void onAnimationEnd(Animator animator) {
if (animator == mCenteringAnimator && !mBurnInProtectionActive) {
+ mAppliedBurnInXOffset = 0;
+ mAppliedBurnInYOffset = 0;
// No matter how the animation finishes, we want to zero the offsets.
mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
}
@@ -276,7 +283,7 @@ public void onAnimationUpdate(ValueAnimator valueAnimator) {
if (!mBurnInProtectionActive) {
final float value = (Float) valueAnimator.getAnimatedValue();
mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
- (int) (mLastBurnInXOffset * value), (int) (mLastBurnInYOffset * value));
+ (int) (mAppliedBurnInXOffset * value), (int) (mAppliedBurnInYOffset * value));
}
}
}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 8c42917a8bf2c..96e1c70c2dc4e 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -22,12 +22,14 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.R;
+import com.android.internal.util.UserIcons;
import com.android.internal.widget.LockPatternUtils;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.INotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -35,12 +37,18 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ThemeUtils;
import android.content.pm.UserInfo;
import android.content.ServiceConnection;
import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.Manifest;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
@@ -58,10 +66,13 @@
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -84,11 +95,14 @@
import android.widget.ImageView.ScaleType;
import android.widget.ListView;
import android.widget.TextView;
+
import cyanogenmod.providers.CMSettings;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.List;
-import java.util.UUID;
+
+import org.cyanogenmod.internal.util.ThemeUtils;
import static com.android.internal.util.cm.PowerMenuConstants.*;
@@ -128,6 +142,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
// Power menu customizations
String mActions;
+ private BitSet mAirplaneModeBits;
+ private final List mPhoneStateListeners = new ArrayList<>();
+
/**
* @param context everything needs a context :(
*/
@@ -151,9 +168,15 @@ public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
// get notified of phone state changes
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
+ new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ super.onSubscriptionsChanged();
+ setupAirplaneModeListeners();
+ }
+ });
+ setupAirplaneModeListeners();
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
mAirplaneModeObserver);
@@ -166,6 +189,58 @@ public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
updatePowerMenuActions();
}
+ /**
+ * Since there are two ways of handling airplane mode (with telephony, we depend on the internal
+ * device telephony state), and MSIM devices do not report phone state for missing SIMs, we
+ * need to dynamically setup listeners based on subscription changes.
+ *
+ * So if there is _any_ active SIM in the device, we can depend on the phone state,
+ * otherwise fall back to {@link Settings.Global#AIRPLANE_MODE_ON}.
+ */
+ private void setupAirplaneModeListeners() {
+ TelephonyManager telephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+ for (PhoneStateListener listener : mPhoneStateListeners) {
+ telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);
+ }
+ mPhoneStateListeners.clear();
+
+ final List subInfoList = SubscriptionManager.from(mContext)
+ .getActiveSubscriptionInfoList();
+ if (subInfoList != null) {
+ mHasTelephony = true;
+ mAirplaneModeBits = new BitSet(subInfoList.size());
+ for (int i = 0; i < subInfoList.size(); i++) {
+ final int finalI = i;
+ PhoneStateListener subListener = new PhoneStateListener(subInfoList.get(finalI)
+ .getSubscriptionId()) {
+ @Override
+ public void onServiceStateChanged(ServiceState serviceState) {
+ final boolean inAirplaneMode = serviceState.getState()
+ == ServiceState.STATE_POWER_OFF;
+ mAirplaneModeBits.set(finalI, inAirplaneMode);
+
+ // we're in airplane mode if _any_ of the subscriptions say we are
+ mAirplaneState = mAirplaneModeBits.cardinality() > 0
+ ? ToggleAction.State.On : ToggleAction.State.Off;
+
+ mAirplaneModeOn.updateState(mAirplaneState);
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+ mPhoneStateListeners.add(subListener);
+ telephonyManager.listen(subListener, PhoneStateListener.LISTEN_SERVICE_STATE);
+ }
+ } else {
+ mHasTelephony = false;
+ }
+ // Set the initial status of airplane mode toggle
+ mAirplaneState = getUpdatedAirplaneToggleState();
+ }
+
/**
* Show the global actions dialog (creating if necessary)
* @param keyguardShowing True if keyguard is showing
@@ -173,14 +248,12 @@ public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
- if (mDialog != null && mUiContext == null) {
+ if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
- mDialog = createDialog();
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
- mDialog = createDialog();
handleShow();
}
}
@@ -199,6 +272,7 @@ private void awakenIfNecessary() {
private void handleShow() {
awakenIfNecessary();
+ mDialog = createDialog();
prepareDialog();
// If we only have 1 item and it's a simple press action, just do this action.
@@ -218,7 +292,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;
}
@@ -342,7 +416,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);
@@ -612,16 +687,24 @@ private void addUsersToMenu(ArrayList items) {
if (um.isUserSwitcherEnabled()) {
List users = um.getUsers();
UserInfo currentUser = getCurrentUser();
+ final int avatarSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.global_actions_avatar_size);
for (final UserInfo user : users) {
if (user.supportsSwitchTo()) {
boolean isCurrentUser = currentUser == null
? user.id == 0 : (currentUser.id == user.id);
- Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
- : null;
+ Drawable avatar = null;
+ Bitmap rawAvatar = um.getUserIcon(user.id);
+ if (rawAvatar == null) {
+ rawAvatar = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
+ user.isGuest() ? UserHandle.USER_NULL : user.id, /*light=*/ false));
+ }
+ avatar = new BitmapDrawable(mContext.getResources(),
+ createCircularClip(rawAvatar, avatarSize, avatarSize));
+
SinglePressAction switchToUser = new SinglePressAction(
- com.android.internal.R.drawable.ic_lock_user, icon,
- (user.name != null ? user.name : "Primary")
- + (isCurrentUser ? " \u2714" : "")) {
+ com.android.internal.R.drawable.ic_lock_user, avatar,
+ (user.name != null ? user.name : "Primary")) {
public void onPress() {
try {
ActivityManagerNative.getDefault().switchUser(user.id);
@@ -638,6 +721,10 @@ public boolean showBeforeProvisioning() {
return false;
}
};
+ if (isCurrentUser) {
+ switchToUser.setStatus(mContext.getString(
+ R.string.global_action_current_user));
+ }
items.add(switchToUser);
}
}
@@ -721,7 +808,8 @@ public void handleMessage(Message msg) {
@Override
public void onServiceDisconnected(ComponentName name) {}
};
- if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
+ if (mContext.bindServiceAsUser(
+ intent, conn, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
mScreenshotConnection = conn;
mHandler.postDelayed(mScreenshotTimeout, 10000);
}
@@ -890,6 +978,7 @@ private static abstract class SinglePressAction implements Action {
private final Drawable mIcon;
private final int mMessageResId;
private final CharSequence mMessage;
+ private CharSequence mStatusMessage;
protected SinglePressAction(int iconResId, int messageResId) {
mIconResId = iconResId;
@@ -916,8 +1005,12 @@ public boolean isEnabled() {
return true;
}
- public String getStatus() {
- return null;
+ public CharSequence getStatus() {
+ return mStatusMessage;
+ }
+
+ public void setStatus(CharSequence status) {
+ mStatusMessage = status;
}
abstract public void onPress();
@@ -938,7 +1031,7 @@ public View create(
TextView messageView = (TextView) v.findViewById(R.id.message);
TextView statusView = (TextView) v.findViewById(R.id.status);
- final String status = getStatus();
+ final CharSequence status = getStatus();
if (!TextUtils.isEmpty(status)) {
statusView.setText(status);
} else {
@@ -946,7 +1039,7 @@ public View create(
}
if (mIcon != null) {
icon.setImageDrawable(mIcon);
- icon.setScaleType(ScaleType.CENTER_CROP);
+ icon.setScaleType(ScaleType.CENTER);
} else if (mIconResId != 0) {
icon.setImageDrawable(context.getDrawable(mIconResId));
}
@@ -1116,9 +1209,15 @@ public boolean showBeforeProvisioning() {
}
}
- private static class SilentModeTriStateAction implements Action, View.OnClickListener {
+ private final class SilentModeTriStateAction implements Action, View.OnClickListener {
- private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
+ private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3, R.id.option4 };
+ private final int[] ITEM_INDEX_TO_ZEN_MODE = {
+ Global.ZEN_MODE_NO_INTERRUPTIONS,
+ Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ Global.ZEN_MODE_OFF,
+ Global.ZEN_MODE_OFF
+ };
private final AudioManager mAudioManager;
private final Handler mHandler;
@@ -1130,14 +1229,15 @@ private static class SilentModeTriStateAction implements Action, View.OnClickLis
mContext = context;
}
- private int ringerModeToIndex(int ringerMode) {
- // They just happen to coincide
- return ringerMode;
- }
-
private int indexToRingerMode(int index) {
- // They just happen to coincide
- return index;
+ if (index == 2) {
+ if (mHasVibrator) {
+ return AudioManager.RINGER_MODE_VIBRATE;
+ } else {
+ return AudioManager.RINGER_MODE_NORMAL;
+ }
+ }
+ return AudioManager.RINGER_MODE_NORMAL;
}
@Override
@@ -1149,9 +1249,28 @@ public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
- int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
- for (int i = 0; i < 3; i++) {
+ int ringerMode = mAudioManager.getRingerModeInternal();
+ int zenMode = Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE,
+ Global.ZEN_MODE_OFF);
+ int selectedIndex = 0;
+ if (zenMode != Global.ZEN_MODE_OFF) {
+ if (zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+ selectedIndex = 0;
+ } else if (zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+ selectedIndex = 1;
+ }
+ } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ selectedIndex = 2;
+ } else if (ringerMode == AudioManager.RINGER_MODE_NORMAL) {
+ selectedIndex = 3;
+ }
+
+ for (int i = 0; i < ITEM_IDS.length; i++) {
View itemView = v.findViewById(ITEM_IDS[i]);
+ if (!mHasVibrator && i == 2) {
+ itemView.setVisibility(View.GONE);
+ continue;
+ }
itemView.setSelected(selectedIndex == i);
// Set up click handler
itemView.setTag(i);
@@ -1182,7 +1301,22 @@ public void onClick(View v) {
if (!(v.getTag() instanceof Integer)) return;
int index = (Integer) v.getTag();
- mAudioManager.setRingerMode(indexToRingerMode(index));
+ int zenMode = ITEM_INDEX_TO_ZEN_MODE[index];
+ // ZenModeHelper will revert zen mode back to the previous value if we just
+ // put the value into the Settings db, so use INotificationManager instead
+ INotificationManager noMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ try {
+ noMan.setZenMode(zenMode, null, TAG);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to set zen mode", e);
+ }
+
+ if (index == 2 || index == 3) {
+ int ringerMode = indexToRingerMode(index);
+ mAudioManager.setRingerModeInternal(ringerMode);
+ }
+ mAdapter.notifyDataSetChanged();
mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
}
}
@@ -1222,17 +1356,6 @@ public void onReceive(Context context, Intent intent) {
}
};
- PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- if (!mHasTelephony) return;
- final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
- mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
- mAirplaneModeOn.updateState(mAirplaneState);
- mAdapter.notifyDataSetChanged();
- }
- };
-
private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1274,15 +1397,17 @@ public void handleMessage(Message msg) {
}
};
+ private ToggleAction.State getUpdatedAirplaneToggleState() {
+ return (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1) ?
+ ToggleAction.State.On : ToggleAction.State.Off;
+ }
+
private void onAirplaneModeChanged() {
// Let the service state callbacks handle the state.
if (mHasTelephony) return;
- boolean airplaneModeOn = Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON,
- 0) == 1;
- mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
+ mAirplaneState = getUpdatedAirplaneToggleState();
mAirplaneModeOn.updateState(mAirplaneState);
}
@@ -1303,8 +1428,36 @@ private void changeAirplaneModeSystemSetting(boolean on) {
}
}
+ /**
+ * Generate a new bitmap (width x height pixels, ARGB_8888) with the input bitmap scaled
+ * to fit and clipped to an inscribed circle.
+ * @param input Bitmap to resize and clip
+ * @param width Width of output bitmap (and diameter of circle)
+ * @param height Height of output bitmap
+ * @return A shiny new bitmap for you to use
+ */
+ private static Bitmap createCircularClip(Bitmap input, int width, int height) {
+ if (input == null) return null;
+
+ final int inWidth = input.getWidth();
+ final int inHeight = input.getHeight();
+ final Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(output);
+ final Paint paint = new Paint();
+ paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ paint.setAntiAlias(true);
+ final RectF srcRect = new RectF(0, 0, inWidth, inHeight);
+ final RectF dstRect = new RectF(0, 0, width, height);
+ final Matrix m = new Matrix();
+ m.setRectToRect(srcRect, dstRect, Matrix.ScaleToFit.CENTER);
+ canvas.setMatrix(m);
+ canvas.drawCircle(inWidth / 2, inHeight / 2, inWidth / 2, paint);
+ return output;
+ }
+
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;
@@ -1314,7 +1467,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());
@@ -1323,6 +1476,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,
@@ -1336,8 +1502,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 dd4d3abe7099c..63390073e3dc2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -22,7 +22,6 @@
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
-import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.StatusBarManager;
import android.app.UiModeManager;
@@ -36,6 +35,7 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.CompatibilityInfo;
@@ -83,10 +83,11 @@
import android.service.dreams.IDreamManager;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
-import android.service.gesture.EdgeGestureManager;
import com.android.internal.os.DeviceKeyHandler;
import com.android.internal.util.cm.ActionUtils;
+
+import cyanogenmod.hardware.CMHardwareManager;
import cyanogenmod.providers.CMSettings;
import dalvik.system.DexClassLoader;
import android.util.DisplayMetrics;
@@ -129,8 +130,6 @@
import com.android.internal.policy.IKeyguardService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ScreenShapeHelper;
-import com.android.internal.util.gesture.EdgeGesturePosition;
-import com.android.internal.util.gesture.EdgeServiceConstants;
import com.android.internal.view.RotationPolicy;
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
@@ -138,6 +137,8 @@
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
+import org.cyanogenmod.internal.BootDexoptDialog;
+
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
@@ -153,6 +154,7 @@
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
+import static org.cyanogenmod.platform.internal.Manifest.permission.THIRD_PARTY_KEYGUARD;
/**
* WindowManagerPolicy implementation for the Android phone UI. This
@@ -274,6 +276,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// app shows again. If that doesn't happen for 30s we drop the gesture.
private static final long PANIC_GESTURE_EXPIRATION = 30000;
+ private static final String DEPRECATED_THIRD_PARTY_KEYGUARD_PERMISSION =
+ "android.permission.THIRD_PARTY_KEYGUARD";
+
/**
* Keyguard stuff
*/
@@ -372,6 +377,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int[] mNavigationBarHeightForRotation = new int[4];
int[] mNavigationBarWidthForRotation = new int[4];
+ WindowState mKeyguardPanel;
+
KeyguardServiceDelegate mKeyguardDelegate;
final Runnable mWindowManagerDrawCallback = new Runnable() {
@Override
@@ -488,7 +495,9 @@ public void onDrawn() {
// During wakeup by volume keys, we still need to capture subsequent events
// until the key is released. This is required since the beep sound is produced
// post keypressed.
- boolean mVolumeWakeTriggered;
+ boolean mVolumeDownWakeTriggered;
+ boolean mVolumeUpWakeTriggered;
+ boolean mVolumeMuteWakeTriggered;
int mPointerLocationMode = 0; // guarded by mLock
@@ -654,6 +663,10 @@ public void onDrawn() {
// (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.)
int mIncallPowerBehavior;
+ // Behavior of HOME button during incomming call ring.
+ // (See Settings.Secure.RING_HOME_BUTTON_BEHAVIOR.)
+ int mRingHomeBehavior;
+
Display mDisplay;
private int mDisplayRotation;
@@ -743,6 +756,8 @@ public void onDrawn() {
private boolean mHasPermanentMenuKey;
private boolean mClearedBecauseOfForceShow;
private boolean mTopWindowIsKeyguard;
+ private CMHardwareManager mCMHardware;
+ private boolean mShowKeyguardOnLeftSwipe;
private class PolicyHandler extends Handler {
@Override
@@ -832,6 +847,9 @@ void observe() {
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
+ CMSettings.Secure.RING_HOME_BUTTON_BEHAVIOR), false, this,
+ UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.WAKE_GESTURE_ENABLED), false, this,
UserHandle.USER_ALL);
@@ -883,15 +901,12 @@ 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,
UserHandle.USER_ALL);
- resolver.registerContentObserver(CMSettings.System.getUriFor(
- CMSettings.System.USE_EDGE_SERVICE_FOR_GESTURES), false, this,
- UserHandle.USER_ALL);
resolver.registerContentObserver(CMSettings.System.getUriFor(
CMSettings.System.BACK_WAKE_SCREEN), false, this,
UserHandle.USER_ALL);
@@ -986,67 +1001,6 @@ public void onProposedRotationChanged(int rotation) {
private SystemGesturesPointerEventListener mSystemGestures;
- private EdgeGestureManager.EdgeGestureActivationListener mEdgeGestureActivationListener
- = new EdgeGestureManager.EdgeGestureActivationListener() {
-
- @Override
- public void onEdgeGestureActivation(int touchX, int touchY,
- EdgeGesturePosition position, int flags) {
- WindowState target = null;
-
- if (position == EdgeGesturePosition.TOP) {
- target = mStatusBar;
- } else if (position == EdgeGesturePosition.BOTTOM && mNavigationBarOnBottom) {
- target = mNavigationBar;
- } else if (position == EdgeGesturePosition.LEFT
- && !mNavigationBarOnBottom && mNavigationBarLeftInLandscape) {
- target = mNavigationBar;
- } else if (position == EdgeGesturePosition.RIGHT && !mNavigationBarOnBottom) {
- target = mNavigationBar;
- }
-
- if (target != null) {
- requestTransientBars(target);
- dropEventsUntilLift();
- mEdgeListenerActivated = true;
- } else {
- restoreListenerState();
- }
- }
- };
- private EdgeGestureManager mEdgeGestureManager = null;
- private int mLastEdgePositions = 0;
- private boolean mEdgeListenerActivated = false;
- private boolean mUsingEdgeGestureServiceForGestures = false;
-
- private void updateEdgeGestureListenerState() {
- int flags = 0;
- if (mUsingEdgeGestureServiceForGestures) {
- flags = EdgeServiceConstants.LONG_LIVING | EdgeServiceConstants.UNRESTRICTED;
- if (mStatusBar != null && !mStatusBar.isVisibleLw()) {
- flags |= EdgeGesturePosition.TOP.FLAG;
- }
- if (mNavigationBar != null && !mNavigationBar.isVisibleLw() && !isStatusBarKeyguard()) {
- if (mNavigationBarOnBottom) {
- flags |= EdgeGesturePosition.BOTTOM.FLAG;
- } else if (mNavigationBarLeftInLandscape) {
- flags |= EdgeGesturePosition.LEFT.FLAG;
- } else {
- flags |= EdgeGesturePosition.RIGHT.FLAG;
- }
- }
- }
- if (mEdgeListenerActivated) {
- mEdgeGestureActivationListener.restoreListenerState();
- mEdgeListenerActivated = false;
- }
- if (flags != mLastEdgePositions) {
- mEdgeGestureManager.updateEdgeGestureActivationListener(mEdgeGestureActivationListener,
- flags);
- mLastEdgePositions = flags;
- }
- }
-
IStatusBarService getStatusBarService() {
synchronized (mServiceAquireLock) {
if (mStatusBarService == null) {
@@ -1489,8 +1443,8 @@ boolean isDeviceProvisioned() {
}
boolean isUserSetupComplete() {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ return CMSettings.Secure.getIntForUser(mContext.getContentResolver(),
+ CMSettings.Secure.CM_SETUP_WIZARD_COMPLETED, 0, UserHandle.USER_CURRENT) != 0;
}
private void handleShortPressOnHome() {
@@ -1625,6 +1579,7 @@ public void init(Context context, IWindowManager windowManager,
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
// Init display burn-in protection
boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -1668,7 +1623,6 @@ public void init(Context context, IWindowManager windowManager,
mOrientationListener.setCurrentRotation(windowManager.getRotation());
} catch (RemoteException ex) { }
mSettingsObserver = new SettingsObserver(mHandler);
- mSettingsObserver.observe();
mShortcutManager = new ShortcutManager(context);
mUiMode = context.getResources().getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
@@ -1813,6 +1767,11 @@ public void onSwipeFromLeft() {
mNavigationBarLeftInLandscape) {
requestTransientBars(mNavigationBar);
}
+ if (mShowKeyguardOnLeftSwipe && isKeyguardShowingOrOccluded()
+ && mKeyguardDelegate.isKeyguardPanelFocused()) {
+ // Show keyguard
+ mKeyguardDelegate.showKeyguard();
+ }
}
@Override
public void onFling(int duration) {
@@ -2136,6 +2095,10 @@ public void updateSettings() {
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
UserHandle.USER_CURRENT);
+ mRingHomeBehavior = CMSettings.Secure.getIntForUser(resolver,
+ CMSettings.Secure.RING_HOME_BUTTON_BEHAVIOR,
+ CMSettings.Secure.RING_HOME_BUTTON_BEHAVIOR_DEFAULT,
+ UserHandle.USER_CURRENT);
mHomeWakeScreen = (CMSettings.System.getIntForUser(resolver,
CMSettings.System.HOME_WAKE_SCREEN, 1, UserHandle.USER_CURRENT) == 1) &&
((mDeviceHardwareWakeKeys & KEY_MASK_HOME) != 0);
@@ -2173,23 +2136,13 @@ public void updateSettings() {
updateWakeGestureListenerLp();
}
- final boolean useEdgeService = CMSettings.System.getIntForUser(resolver,
- CMSettings.System.USE_EDGE_SERVICE_FOR_GESTURES, 1, UserHandle.USER_CURRENT) == 1;
- if (useEdgeService ^ mUsingEdgeGestureServiceForGestures && mSystemReady) {
- if (!mUsingEdgeGestureServiceForGestures && useEdgeService) {
- mUsingEdgeGestureServiceForGestures = true;
- mWindowManagerFuncs.unregisterPointerEventListener(mSystemGestures);
- } else if (mUsingEdgeGestureServiceForGestures && !useEdgeService) {
- mUsingEdgeGestureServiceForGestures = false;
- mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
- }
- updateEdgeGestureListenerState();
- }
-
- 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)) {
+ mCMHardware.set(CMHardwareManager.FEATURE_KEY_DISABLE, mDevForceNavbar);
+ }
}
mNavigationBarLeftInLandscape = CMSettings.System.getIntForUser(resolver,
@@ -2359,6 +2312,9 @@ public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp)
permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
break;
+ case TYPE_KEYGUARD_PANEL:
+ permission = THIRD_PARTY_KEYGUARD;
+ break;
default:
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
@@ -2392,6 +2348,14 @@ public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp)
return WindowManagerGlobal.ADD_OKAY;
}
}
+ } else if (permission == THIRD_PARTY_KEYGUARD) {
+ // check if caller has the old permission and if so allow adding window
+ if (mContext.checkCallingOrSelfPermission(
+ DEPRECATED_THIRD_PARTY_KEYGUARD_PERMISSION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return WindowManagerGlobal.ADD_OKAY;
+ }
+ // fall through to the normal check below
}
if (mContext.checkCallingOrSelfPermission(permission)
@@ -2440,6 +2404,7 @@ public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
case TYPE_SYSTEM_DIALOG:
case TYPE_VOLUME_OVERLAY:
case TYPE_PRIVATE_PRESENTATION:
+ case TYPE_KEYGUARD_PANEL:
break;
}
@@ -2482,6 +2447,12 @@ public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
+
+ if ((attrs.privateFlags & (WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_SYSTEM_KEYS |
+ WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY)) != 0) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.PREVENT_SYSTEM_KEYS,
+ "No permission to prevent system key");
+ }
}
void readLidState() {
@@ -2578,6 +2549,7 @@ public int windowTypeToLayerLw(int type) {
// the safety window that shows behind keyguard while keyguard is starting
return 14;
case TYPE_STATUS_BAR_SUB_PANEL:
+ case TYPE_KEYGUARD_PANEL:
return 15;
case TYPE_STATUS_BAR:
return 16;
@@ -2724,6 +2696,11 @@ public WindowState getWinShowWhenLockedLw() {
return mWinShowWhenLocked;
}
+ @Override
+ public WindowState getWinKeyguardPanelLw() {
+ return mKeyguardPanel;
+ }
+
/** {@inheritDoc} */
@Override
public View addStartingWindow(IBinder appToken, String packageName, int theme,
@@ -2918,6 +2895,19 @@ public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs)
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
break;
+ case TYPE_KEYGUARD_PANEL:
+ // check deprecated perm first and if not granted enforce the new permission name
+ if (mContext.checkCallingOrSelfPermission(
+ DEPRECATED_THIRD_PARTY_KEYGUARD_PERMISSION)
+ != PackageManager.PERMISSION_GRANTED) {
+ mContext.enforceCallingOrSelfPermission(THIRD_PARTY_KEYGUARD,
+ "PhoneWindowManager");
+ }
+ if (mKeyguardPanel != null) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ mKeyguardPanel = win;
+ break;
case TYPE_KEYGUARD_SCRIM:
if (mKeyguardScrim != null) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
@@ -2938,9 +2928,11 @@ public void removeWindowLw(WindowState win) {
} else if (mKeyguardScrim == win) {
Log.v(TAG, "Removing keyguard scrim");
mKeyguardScrim = null;
- } if (mNavigationBar == win) {
+ } else if (mNavigationBar == win) {
mNavigationBar = null;
mNavigationBarController.setWindow(null);
+ } else if (mKeyguardPanel == win) {
+ mKeyguardPanel = null;
}
}
@@ -3137,19 +3129,6 @@ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int p
+ " canceled=" + canceled);
}
- // If the boot mode is power off alarm, we should not dispatch the several physical keys
- // in power off alarm UI to avoid pausing power off alarm UI.
- int isPowerOffAlarmMode = Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.POWER_OFF_ALARM_MODE, 0);
- if (DEBUG_INPUT) { Log.d(TAG, "intercept Dispatching isPowerOffAlarmMode = " +
- isPowerOffAlarmMode); }
-
- if (isPowerOffAlarmMode == 1 && (keyCode == KeyEvent.KEYCODE_HOME
- || keyCode == KeyEvent.KEYCODE_SEARCH
- || keyCode == KeyEvent.KEYCODE_MENU)) {
- return -1; // ignore the physical key here
- }
-
// If we think we might have a volume down & power key chord on the way
// but we're not sure, then tell the dispatcher to wait a little while and
// try again later before dispatching.
@@ -3187,6 +3166,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) {
@@ -3210,8 +3195,15 @@ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int p
// and his ONLY options are to answer or reject the call.)
TelecomManager telecomManager = getTelecommService();
if (telecomManager != null && telecomManager.isRinging()) {
- Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
- return -1;
+ if ((mRingHomeBehavior
+ & CMSettings.Secure.RING_HOME_BUTTON_BEHAVIOR_ANSWER) != 0) {
+ Log.i(TAG, "Answering with HOME button.");
+ telecomManager.acceptRingingCall();
+ return -1;
+ } else {
+ Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+ return -1;
+ }
}
// Delay handling home if a double-tap is possible.
@@ -3280,6 +3272,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) {
@@ -3345,6 +3344,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
@@ -4005,8 +4011,6 @@ public int adjustSystemUiVisibilityLw(int visibility) {
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
- updateEdgeGestureListenerState();
-
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
mResettingSystemUiFlags &= visibility;
@@ -4462,7 +4466,12 @@ private void applyForceImmersiveMode(int pfl, Rect r) {
}
}
- private void applyStableConstraints(int sysui, int fl, Rect r) {
+ private void applyStableConstraints(int sysui, int fl, Rect r, Rect d) {
+ if (mNavigationBarLeftInLandscape) {
+ d.left = r.left;
+ r.left = 0;
+ }
+
if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
// If app is requesting a stable layout, don't let the
// content insets go below the stable values.
@@ -4722,7 +4731,7 @@ public void layoutWindowLw(WindowState win, WindowState attached) {
cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
}
- applyStableConstraints(sysUiFl, fl, cf);
+ applyStableConstraints(sysUiFl, fl, cf, df);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.left = mCurLeft;
vf.top = mCurTop;
@@ -4743,7 +4752,8 @@ public void layoutWindowLw(WindowState win, WindowState attached) {
// gets everything, period.
if (attrs.type == TYPE_STATUS_BAR_PANEL
|| attrs.type == TYPE_STATUS_BAR_SUB_PANEL
- || attrs.type == TYPE_VOLUME_OVERLAY) {
+ || attrs.type == TYPE_VOLUME_OVERLAY
+ || attrs.type == TYPE_KEYGUARD_PANEL) {
pf.left = df.left = of.left = cf.left = hasNavBar
? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
@@ -4837,7 +4847,7 @@ public void layoutWindowLw(WindowState win, WindowState attached) {
+ mRestrictedScreenHeight;
}
- applyStableConstraints(sysUiFl, fl, cf);
+ applyStableConstraints(sysUiFl, fl, cf, df);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
vf.left = mCurLeft;
@@ -5053,7 +5063,15 @@ public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams
if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
mForceStatusBarTransparent = true;
}
- }
+ } else if (attrs.type == TYPE_KEYGUARD_PANEL) {
+ if (mKeyguardDelegate.isKeyguardPanelFocused()) {
+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ attrs.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ } else {
+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ }
+ }
boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type < FIRST_SYSTEM_WINDOW;
@@ -5329,7 +5347,6 @@ public void run() {
// update since mAllowLockscreenWhenOn might have changed
updateLockScreenTimeout();
- updateEdgeGestureListenerState();
return changes;
}
@@ -5557,6 +5574,36 @@ public void onServiceDisconnected(ComponentName name) {}
}
}
+ private void setVolumeWakeTriggered(final int keyCode, boolean triggered) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ mVolumeDownWakeTriggered = triggered;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ mVolumeUpWakeTriggered = triggered;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ mVolumeMuteWakeTriggered = triggered;
+ break;
+ default:
+ Log.w(TAG, "setVolumeWakeTriggered: unexpected keyCode=" + keyCode);
+ }
+ }
+
+ private boolean getVolumeWakeTriggered(final int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ return mVolumeDownWakeTriggered;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ return mVolumeUpWakeTriggered;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return mVolumeMuteWakeTriggered;
+ default:
+ Log.w(TAG, "getVolumeWakeTriggered: unexpected keyCode=" + keyCode);
+ return false;
+ }
+ }
+
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -5618,7 +5665,8 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
+ "android.policy:KEY", true);
}
return result;
}
@@ -5651,11 +5699,11 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
// Eat all down & up keys when using volume wake.
// This disables volume control, music control, and "beep" on key up.
if (isWakeKey && mVolumeWakeScreen) {
- mVolumeWakeTriggered = true;
+ setVolumeWakeTriggered(keyCode, true);
break;
- } else if (mVolumeWakeTriggered && !down) {
+ } else if (getVolumeWakeTriggered(keyCode) && !down) {
result &= ~ACTION_PASS_TO_USER;
- mVolumeWakeTriggered = false;
+ setVolumeWakeTriggered(keyCode, false);
break;
}
@@ -5853,7 +5901,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;
}
@@ -5881,6 +5930,15 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
break;
}
+ case KeyEvent.KEYCODE_SOFT_SLEEP: {
+ result &= ~ACTION_PASS_TO_USER;
+ isWakeKey = false;
+ if (!down) {
+ mPowerManagerInternal.setUserInactiveOverrideFromWindowManager();
+ }
+ break;
+ }
+
case KeyEvent.KEYCODE_WAKEUP: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = true;
@@ -5956,7 +6014,8 @@ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
}
if (isWakeKey) {
- wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
+ wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY",
+ event.getKeyCode() == KeyEvent.KEYCODE_WAKEUP /* check prox only on wake key*/);
}
return result;
@@ -6093,11 +6152,9 @@ public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int polic
}
private boolean shouldDispatchInputWhenNonInteractive() {
- if (mDisplay == null || mDisplay.getState() == Display.STATE_OFF) {
- return false;
- }
- // Send events to keyguard while the screen is on and it's showing.
- if (isKeyguardShowingAndNotOccluded()) {
+ // Send events to keyguard while the screen is on.
+ if (isKeyguardShowingAndNotOccluded() && mDisplay != null
+ && mDisplay.getState() != Display.STATE_OFF) {
return true;
}
@@ -6400,6 +6457,11 @@ private void wakeUpFromPowerKey(long eventTime) {
}
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
+ return wakeUp(wakeTime, wakeInTheaterMode, reason, false);
+ }
+
+ private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason,
+ boolean withProximityCheck) {
final boolean theaterModeEnabled = isTheaterModeEnabled();
if (!wakeInTheaterMode && theaterModeEnabled) {
return false;
@@ -6410,7 +6472,11 @@ private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason)
Settings.Global.THEATER_MODE_ON, 0);
}
- mPowerManager.wakeUp(wakeTime, reason);
+ if (withProximityCheck) {
+ mPowerManager.wakeUpWithProximityCheck(wakeTime, reason);
+ } else {
+ mPowerManager.wakeUp(wakeTime, reason);
+ }
return true;
}
@@ -6925,8 +6991,10 @@ public void systemReady() {
mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
mKeyguardDelegate.onSystemReady();
- mEdgeGestureManager = EdgeGestureManager.getInstance();
- mEdgeGestureManager.setEdgeGestureActivationListener(mEdgeGestureActivationListener);
+ mCMHardware = CMHardwareManager.getInstance(mContext);
+ // Ensure observe happens in systemReady() since we need
+ // CMHardwareService to be up and running
+ mSettingsObserver.observe();
readCameraLensCoverState();
updateUiMode();
@@ -6982,68 +7050,18 @@ public void systemBooted() {
screenTurnedOn();
}
- ProgressDialog mBootMsgDialog = null;
+ BootDexoptDialog mBootMsgDialog = null;
/** {@inheritDoc} */
@Override
- public void showBootMessage(final CharSequence msg, final boolean always) {
+ public void updateBootProgress(final int stage, final ApplicationInfo optimizedApp,
+ final int currentAppPos, final int totalAppCount) {
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
- int theme;
- if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WATCH)) {
- theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
- } else if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEVISION)) {
- theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
- } else {
- theme = 0;
- }
-
- mBootMsgDialog = new ProgressDialog(mContext, theme) {
- // This dialog will consume all events coming in to
- // it, to avoid it trying to do things too early in boot.
- @Override public boolean dispatchKeyEvent(KeyEvent event) {
- return true;
- }
- @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) {
- return true;
- }
- @Override public boolean dispatchTouchEvent(MotionEvent ev) {
- return true;
- }
- @Override public boolean dispatchTrackballEvent(MotionEvent ev) {
- return true;
- }
- @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) {
- return true;
- }
- @Override public boolean dispatchPopulateAccessibilityEvent(
- AccessibilityEvent event) {
- return true;
- }
- };
- if (mContext.getPackageManager().isUpgrade()) {
- mBootMsgDialog.setTitle(R.string.android_upgrading_title);
- } else {
- mBootMsgDialog.setTitle(R.string.android_start_title);
- }
- mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
- mBootMsgDialog.setIndeterminate(true);
- mBootMsgDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_BOOT_PROGRESS);
- mBootMsgDialog.getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
- mBootMsgDialog.getWindow().setDimAmount(1);
- WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes();
- lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
- mBootMsgDialog.getWindow().setAttributes(lp);
- mBootMsgDialog.setCancelable(false);
- mBootMsgDialog.show();
- }
- mBootMsgDialog.setMessage(msg);
+ mBootMsgDialog = BootDexoptDialog.create(mContext);
+ }
+ mBootMsgDialog.setProgress(stage, optimizedApp, currentAppPos, totalAppCount);
}
});
}
@@ -7808,6 +7826,7 @@ public void dump(String prefix, PrintWriter pw, String[] args) {
pw.print(prefix);
pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
+ pw.print(" mRingHomeBehavior="); pw.print(mRingHomeBehavior);
pw.print(prefix);
pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior);
pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior);
@@ -7959,4 +7978,9 @@ public void dump(String prefix, PrintWriter pw, String[] args) {
mKeyguardDelegate.dump(prefix, pw);
}
}
+
+ @Override
+ public void setLiveLockscreenEdgeDetector(boolean enable) {
+ mShowKeyguardOnLeftSwipe = enable;
+ }
}
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 991622398a481..651ee2249dbfc 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -55,6 +55,7 @@ public abstract class WindowOrientationListener {
private boolean mEnabled;
private int mRate;
private String mSensorType;
+ private boolean mUseSystemClockforRotationSensor;
private Sensor mSensor;
private OrientationJudge mOrientationJudge;
private int mCurrentRotation = -1;
@@ -90,6 +91,9 @@ private WindowOrientationListener(Context context, Handler handler, int rate) {
mSensorType = context.getResources().getString(
com.android.internal.R.string.config_orientationSensorType);
+ mUseSystemClockforRotationSensor = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useSystemClockforRotationSensor);
+
if (!TextUtils.isEmpty(mSensorType)) {
List sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
final int N = sensors.size();
@@ -598,7 +602,8 @@ public void onSensorChanged(SensorEvent event) {
// Reset the orientation listener state if the samples are too far apart in time
// or when we see values of (0, 0, 0) which indicates that we polled the
// accelerometer too soon after turning it on and we don't have any data yet.
- final long now = event.timestamp;
+ final long now = mUseSystemClockforRotationSensor
+ ? SystemClock.elapsedRealtimeNanos() : event.timestamp;
final long then = mLastFilteredTimestampNanos;
final float timeDeltaMS = (now - then) * 0.000001f;
final boolean skipSample;
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index cb09dd41d3a0f..a223d056854d4 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -431,4 +431,15 @@ public void dump(String prefix, PrintWriter pw) {
mKeyguardService.dump(prefix, pw);
}
}
+
+ public void showKeyguard() {
+ mKeyguardService.showKeyguard();
+ }
+
+ public boolean isKeyguardPanelFocused() {
+ if (mKeyguardService != null) {
+ return mKeyguardService.isKeyguardPanelFocused();
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 429b18866a61a..31c7a046402ac 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -245,4 +245,16 @@ public boolean isInputRestricted() {
public void dump(String prefix, PrintWriter pw) {
mKeyguardStateMonitor.dump(prefix, pw);
}
+
+ public void showKeyguard() {
+ try {
+ mService.showKeyguard();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote Exception", e);
+ }
+ }
+
+ public boolean isKeyguardPanelFocused() {
+ return mKeyguardStateMonitor.isKeyguardPanelFocused();
+ }
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 30cff039f11ad..09f908711e3da 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -43,6 +43,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
private volatile boolean mIsShowing = true;
private volatile boolean mSimSecure = true;
private volatile boolean mInputRestricted = true;
+ private volatile boolean mKeyguardPanelFocused = false;
private int mCurrentUserId;
@@ -70,6 +71,10 @@ public boolean isInputRestricted() {
return mInputRestricted;
}
+ public boolean isKeyguardPanelFocused() {
+ return mKeyguardPanelFocused;
+ }
+
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
@@ -80,6 +85,11 @@ public void onSimSecureStateChanged(boolean simSecure) {
mSimSecure = simSecure;
}
+ @Override // Binder interface
+ public void onKeyguardPanelFocusChanged(boolean focused) {
+ mKeyguardPanelFocused = focused;
+ }
+
public synchronized void setCurrentUser(int userId) {
mCurrentUserId = userId;
}
@@ -100,5 +110,6 @@ public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "mSimSecure=" + mSimSecure);
pw.println(prefix + "mInputRestricted=" + mInputRestricted);
pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+ pw.println(prefix + "mKeyguardPanelFocused=" + mKeyguardPanelFocused);
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 76d4a27e79157..a197c6ecf12b6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -17,14 +17,18 @@
package com.android.server.power;
import android.app.ActivityManager;
+import android.os.IDeviceIdleController;
+import android.os.ServiceManager;
import android.util.SparseIntArray;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
@@ -108,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;
@@ -135,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;
@@ -179,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;
@@ -278,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;
@@ -434,6 +452,14 @@ public final class PowerManagerService extends SystemService
// Use -1 to disable.
private int mButtonBrightnessOverrideFromWindowManager = -1;
+ // The window manager has determined the user to be inactive via other means.
+ // Set this to false to disable.
+ private boolean mUserInactiveOverrideFromWindowManager;
+
+ // The next possible user activity timeout after being explicitly told the user is inactive.
+ // Set to -1 when not told the user is inactive since the last period spent dozing or asleep.
+ private long mOverriddenTimeout = -1;
+
// The user activity timeout override from the window manager
// to allow the current foreground activity to override the user activity timeout.
// Use -1 to disable.
@@ -516,6 +542,7 @@ public final class PowerManagerService extends SystemService
private boolean mProximityWakeSupported;
android.os.PowerManager.WakeLock mProximityWakeLock;
SensorEventListener mProximityListener;
+ private boolean mForceNavbar;
private PerformanceManagerInternal mPerf;
@@ -530,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;
@@ -690,6 +718,9 @@ mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
resolver.registerContentObserver(CMSettings.Global.getUriFor(
CMSettings.Global.WAKE_WHEN_PLUGGED_OR_UNPLUGGED),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Global.getUriFor(
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR),
+ false, mSettingsObserver, UserHandle.USER_ALL);
// Go.
readConfigurationLocked();
@@ -834,7 +865,8 @@ private void updateSettingsLocked() {
mKeyboardBrightness = CMSettings.Secure.getIntForUser(resolver,
CMSettings.Secure.KEYBOARD_BRIGHTNESS, mKeyboardBrightnessSettingDefault,
UserHandle.USER_CURRENT);
-
+ mForceNavbar = CMSettings.Global.getIntForUser(resolver,
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
mDirty |= DIRTY_SETTINGS;
}
@@ -1151,6 +1183,11 @@ private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags,
mNotifier.onUserActivity(event, uid);
+ if (mUserInactiveOverrideFromWindowManager) {
+ mUserInactiveOverrideFromWindowManager = false;
+ mOverriddenTimeout = -1;
+ }
+
if (mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
@@ -1366,12 +1403,28 @@ private void setWakefulnessLocked(int wakefulness, int reason) {
}
}
+ /**
+ * Logs the time the device would have spent awake before user activity timeout,
+ * had the system not been told the user was inactive.
+ */
+ private void logSleepTimeoutRecapturedLocked() {
+ final long now = SystemClock.uptimeMillis();
+ final long savedWakeTimeMs = mOverriddenTimeout - now;
+ if (savedWakeTimeMs >= 0) {
+ EventLog.writeEvent(EventLogTags.POWER_SOFT_SLEEP_REQUESTED, savedWakeTimeMs);
+ mOverriddenTimeout = -1;
+ }
+ }
+
private void finishWakefulnessChangeIfNeededLocked() {
if (mWakefulnessChanging && mDisplayReady) {
if (mWakefulness == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
}
+ if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) {
+ logSleepTimeoutRecapturedLocked();
+ }
mWakefulnessChanging = false;
mNotifier.onWakefulnessChangeFinished();
}
@@ -1657,6 +1710,7 @@ private void updateUserActivitySummaryLocked(long now, int dirty) {
final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
+ final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
@@ -1670,7 +1724,11 @@ private void updateUserActivitySummaryLocked(long now, int dirty) {
buttonBrightness = mButtonBrightnessOverrideFromWindowManager;
keyboardBrightness = mButtonBrightnessOverrideFromWindowManager;
} else {
- buttonBrightness = mButtonBrightness;
+ if (!mForceNavbar) {
+ buttonBrightness = mButtonBrightness;
+ } else {
+ buttonBrightness = 0;
+ }
keyboardBrightness = mKeyboardBrightness;
}
@@ -1710,6 +1768,7 @@ private void updateUserActivitySummaryLocked(long now, int dirty) {
}
}
}
+
if (mUserActivitySummary == 0) {
if (sleepTimeout >= 0) {
final long anyUserActivity = Math.max(mLastUserActivityTime,
@@ -1725,6 +1784,20 @@ private void updateUserActivitySummaryLocked(long now, int dirty) {
nextTimeout = -1;
}
}
+
+ if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
+ if ((mUserActivitySummary &
+ (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
+ // Device is being kept awake by recent user activity
+ if (nextTimeout >= now && mOverriddenTimeout == -1) {
+ // Save when the next timeout would have occurred
+ mOverriddenTimeout = nextTimeout;
+ }
+ }
+ mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
+ nextTimeout = -1;
+ }
+
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
@@ -1869,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);
}
@@ -1890,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;
@@ -1903,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.
@@ -2332,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;
}
@@ -2654,6 +2757,14 @@ private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness
}
}
+ private void setUserInactiveOverrideFromWindowManagerInternal() {
+ synchronized (mLock) {
+ mUserInactiveOverrideFromWindowManager = true;
+ mDirty |= DIRTY_USER_ACTIVITY;
+ updatePowerStateLocked();
+ }
+ }
+
private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) {
synchronized (mLock) {
if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
@@ -2843,6 +2954,8 @@ private void dumpInternal(PrintWriter pw) {
+ mScreenBrightnessOverrideFromWindowManager);
pw.println(" mUserActivityTimeoutOverrideFromWindowManager="
+ mUserActivityTimeoutOverrideFromWindowManager);
+ pw.println(" mUserInactiveOverrideFromWindowManager="
+ + mUserInactiveOverrideFromWindowManager);
pw.println(" mTemporaryScreenBrightnessSettingOverride="
+ mTemporaryScreenBrightnessSettingOverride);
pw.println(" mTemporaryScreenAutoBrightnessAdjustmentSettingOverride="
@@ -2917,7 +3030,7 @@ private final class DreamReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
- scheduleSandmanLocked();
+ scheduleSandmanLocked(true);
}
}
}
@@ -2974,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();
@@ -2983,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;
}
}
}
@@ -3223,6 +3341,29 @@ public void acquireWakeLock(IBinder lock, int flags, String tag, String packageN
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
+
+ try {
+ if (mAppOps != null &&
+ mAppOps.checkOperation(AppOpsManager.OP_WAKE_LOCK, uid, packageName)
+ != AppOpsManager.MODE_ALLOWED) {
+
+ // If this app is whitelisted as "allow-in-power-save" then always allow!
+ // Current impl only looks at system-loaded ones, if we want to also include
+ // user apps which have been manually set, we would use IDeviceIdleController
+ if (!SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) {
+ Slog.d(TAG, "acquireWakeLock: ignoring request from " + packageName);
+ // For (ignore) accounting purposes
+ mAppOps.noteOperation(AppOpsManager.OP_WAKE_LOCK, uid, packageName);
+ // silent return
+ return;
+ } else {
+ Slog.d(TAG, "wake lock requested to be ignored but " + packageName
+ + " is marked to opt-out of all power save restrictions.");
+ }
+ }
+ } catch (RemoteException ignored) {
+ }
+
final long ident = Binder.clearCallingIdentity();
try {
acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
@@ -3440,6 +3581,8 @@ public void onSensorChanged(SensorEvent event) {
if (distance >= PROXIMITY_NEAR_THRESHOLD ||
distance >= mProximitySensor.getMaximumRange()) {
r.run();
+ } else {
+ Slog.w(TAG, "Not waking up. Proximity sensor blocked.");
}
}
@@ -3775,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();
+ }
}
}
}
@@ -3836,6 +3979,11 @@ public void setDozeOverrideFromDreamManager(int screenState, int screenBrightnes
setDozeOverrideFromDreamManagerInternal(screenState, screenBrightness);
}
+ @Override
+ public void setUserInactiveOverrideFromWindowManager() {
+ setUserInactiveOverrideFromWindowManagerInternal();
+ }
+
@Override
public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 9b8ea1488196d..36a9ca26d9c70 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -26,7 +26,6 @@
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothManager;
-import android.content.pm.ThemeUtils;
import android.media.AudioAttributes;
import android.nfc.NfcAdapter;
import android.nfc.INfcAdapter;
@@ -78,6 +77,8 @@
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
+import org.cyanogenmod.internal.util.ThemeUtils;
+
public final class ShutdownThread extends Thread {
// constants
private static final String TAG = "ShutdownThread";
@@ -629,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.
@@ -664,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);
}
@@ -1001,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/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index a71961c8fe9b7..2185b19cf1bbf 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -309,6 +309,13 @@ public void handleMessage(Message msg) {
}
sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval);
}
+
+ if (!networkLocationEnabled && mLocation == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Network location unavailable");
+ }
+ retrieveLocation();
+ }
break;
case MSG_DO_TWILIGHT_UPDATE:
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index 7c2da2dc292e5..be3e922ad7a6b 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -56,7 +56,7 @@ public CircularDisplayMask(Display display, SurfaceSession session, int zOrder,
int screenOffset, int maskThickness) {
mScreenSize = new Point();
display.getSize(mScreenSize);
- if (mScreenSize.x != mScreenSize.y) {
+ if (mScreenSize.x != mScreenSize.y + screenOffset) {
Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() +
"are not equal, circularMask will not be drawn.");
mDimensionsUnequal = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 331ddbfb6ba3f..2edf5520b449a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -116,6 +116,7 @@ class DisplayContent {
display.getDisplayInfo(mDisplayInfo);
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
+ initializeDisplayBaseInfo();
}
int getDisplayId() {
@@ -176,6 +177,21 @@ void updateDisplayInfo() {
}
}
+ void initializeDisplayBaseInfo() {
+ synchronized(mDisplaySizeLock) {
+ // Bootstrap the default logical display from the display manager.
+ final DisplayInfo newDisplayInfo =
+ mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (newDisplayInfo != null) {
+ mDisplayInfo.copyFrom(newDisplayInfo);
+ }
+ mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+ mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+ mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+ mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+ }
+ }
+
void getLogicalDisplayRect(Rect out) {
// Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
final int orientation = mDisplayInfo.rotation;
diff --git a/services/core/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
index 01f878c1562e7..80526f28ea209 100644
--- a/services/core/java/com/android/server/wm/DisplaySettings.java
+++ b/services/core/java/com/android/server/wm/DisplaySettings.java
@@ -79,17 +79,20 @@ public void getOverscanLocked(String name, String uniqueId, Rect outRect) {
}
}
- public void setOverscanLocked(String name, int left, int top, int right, int bottom) {
+ public void setOverscanLocked(String uniqueId, String name, int left, int top, int right,
+ int bottom) {
if (left == 0 && top == 0 && right == 0 && bottom == 0) {
// Right now all we are storing is overscan; if there is no overscan,
// we have no need for the entry.
+ mEntries.remove(uniqueId);
+ // Legacy name might have been in used, so we need to clear it.
mEntries.remove(name);
return;
}
- Entry entry = mEntries.get(name);
+ Entry entry = mEntries.get(uniqueId);
if (entry == null) {
- entry = new Entry(name);
- mEntries.put(name, entry);
+ entry = new Entry(uniqueId);
+ mEntries.put(uniqueId, entry);
}
entry.overscanLeft = left;
entry.overscanTop = top;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 480da441593fe..7e437c7d96e25 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -399,7 +399,9 @@ void detachDisplay() {
void resetAnimationBackgroundAnimator() {
mAnimationBackgroundAnimator = null;
- mAnimationBackgroundSurface.hide();
+ if (mAnimationBackgroundSurface != null) {
+ mAnimationBackgroundSurface.hide();
+ }
}
private long getBlurBehindFadeDuration(long duration) {
@@ -468,11 +470,14 @@ boolean testDimmingTag() {
}
boolean isDimming() {
+ if (mDimLayer == null) {
+ return false;
+ }
return mDimLayer.isDimming();
}
boolean isDimming(WindowStateAnimator winAnimator) {
- return mDimWinAnimator == winAnimator && mDimLayer.isDimming();
+ return mDimWinAnimator == winAnimator && isDimming();
}
void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 5d9878fdea8ab..362e9590069df 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -30,12 +30,15 @@
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;
import android.util.TimeUtils;
import android.view.Display;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import android.view.WindowManagerPolicy;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -43,6 +46,8 @@
import com.android.server.wm.WindowManagerService.LayoutFields;
+import cyanogenmod.providers.CMSettings;
+
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -97,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;
@@ -119,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) {
@@ -209,6 +219,10 @@ private boolean shouldForceHide(WindowState win) {
allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard;
// 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 &&
+ winShowWhenLocked == null;
+
if (appShowWhenLocked != null) {
allowWhenLocked |= appShowWhenLocked == win.mAppToken
@@ -220,7 +234,14 @@ 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;
+
+ final WindowState winKeyguardPanel = (WindowState) mPolicy.getWinKeyguardPanelLw();
+ // If a keyguard panel is currently being shown, we should
+ // continue to hide the windows as if blur is disabled.
+ if (winKeyguardPanel == null) {
+ keyguardOn &= !mKeyguardBlurEnabled;
+ }
return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY);
}
@@ -229,7 +250,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)) {
@@ -244,7 +265,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;
@@ -334,7 +355,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;
}
}
@@ -887,4 +908,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 60ddd85070068..3d79757230a24 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -29,6 +29,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -65,6 +66,7 @@
import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.ArraySet;
@@ -128,6 +130,8 @@
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
import com.android.server.input.InputManagerService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.power.ShutdownThread;
@@ -1015,7 +1019,6 @@ public void onLowPowerModeChanged(boolean enabled) {
// Load hardware rotation from prop
mSfHwRotation = android.os.SystemProperties.getInt("ro.sf.hwrotation",0) / 90;
- updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
}
@@ -3163,7 +3166,9 @@ public int relayoutWindow(Session session, IWindow client, int seq,
}
if (attrs != null) {
+ Binder.restoreCallingIdentity(origId);
mPolicy.adjustWindowParamsLw(attrs);
+ origId = Binder.clearCallingIdentity();
}
// if they don't have the permission, mask out the status bar bits
@@ -4361,7 +4366,7 @@ public void setAppStartingWindow(IBinder token, String pkg,
AppWindowToken ttoken = findAppWindowToken(transferFrom);
if (ttoken != null) {
WindowState startingWindow = ttoken.startingWindow;
- if (startingWindow != null) {
+ if (startingWindow != null && ttoken.startingView != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
mSkipAppTransitionAnimation = true;
@@ -4490,13 +4495,8 @@ public void setAppStartingWindow(IBinder token, String pkg,
+ " ShowWallpaper="
+ ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowShowWallpaper, false));
- final boolean windowIsTranslucentDefined = ent.array.hasValue(
- com.android.internal.R.styleable.Window_windowIsTranslucent);
- final boolean windowIsTranslucent = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false);
- final boolean windowSwipeToDismiss = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
- if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
+ if (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
return;
}
if (ent.array.getBoolean(
@@ -5934,6 +5934,17 @@ public void performEnableScreen() {
mPolicy.enableScreenAfterBoot();
+ // clear any intrusive lighting which may still be on from the
+ // crypto landing ui
+ LightsManager lm = LocalServices.getService(LightsManager.class);
+ Light batteryLight = lm.getLight(LightsManager.LIGHT_ID_BATTERY);
+ Light notifLight = lm.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+ if (batteryLight != null) {
+ batteryLight.turnOff();
+ }
+ if (notifLight != null) {
+ notifLight.turnOff();
+ }
// Make sure the last requested orientation has been applied.
updateRotationUnchecked(false, false);
}
@@ -5950,13 +5961,18 @@ private boolean checkBootAnimationCompleteLocked() {
return true;
}
- public void showBootMessage(final CharSequence msg, final boolean always) {
+ public void updateBootProgress(final int stage, final ApplicationInfo optimizedApp,
+ final int currentAppPos, final int totalAppCount, final boolean always) {
boolean first = false;
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
- Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
+ Slog.i(TAG, "updateBootProgress: stage=" + stage
+ + " optimizedApp=" + optimizedApp
+ + " currentAppPos=" + currentAppPos
+ + " totalAppCount=" + totalAppCount
+ + " always=" + always
+ " mAllowBootMessages=" + mAllowBootMessages
+ " mShowingBootMessages=" + mShowingBootMessages
+ " mSystemBooted=" + mSystemBooted, here);
@@ -5974,7 +5990,7 @@ public void showBootMessage(final CharSequence msg, final boolean always) {
return;
}
mShowingBootMessages = true;
- mPolicy.showBootMessage(msg, always);
+ mPolicy.updateBootProgress(stage, optimizedApp, currentAppPos, totalAppCount);
}
if (first) {
performEnableScreen();
@@ -6003,7 +6019,7 @@ public void setInTouchMode(boolean mode) {
}
}
- public void updateCircularDisplayMaskIfNeeded() {
+ private void updateCircularDisplayMaskIfNeeded() {
// we're fullscreen and not hosted in an ActivityView
if (mContext.getResources().getConfiguration().isScreenRound()
&& mContext.getResources().getBoolean(
@@ -6043,8 +6059,8 @@ public void showCircularMask(boolean visible) {
if (visible) {
// TODO(multi-display): support multiple displays
if (mCircularDisplayMask == null) {
- int screenOffset = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.circular_display_mask_offset);
+ int screenOffset = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_windowOutsetBottom);
int maskThickness = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.circular_display_mask_thickness);
@@ -7672,6 +7688,12 @@ public boolean detectSafeMode() {
+ " milliseconds before attempting to detect safe mode.");
}
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (um != null && um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
+ mSafeMode = false;
+ return false;
+ }
+
int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
KeyEvent.KEYCODE_MENU);
int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
@@ -7726,6 +7748,8 @@ public void displayReady() {
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
+
+ updateCircularDisplayMaskIfNeeded();
}
private void displayReady(int displayId) {
@@ -7733,22 +7757,7 @@ private void displayReady(int displayId) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
mAnimator.addDisplayLocked(displayId);
- synchronized(displayContent.mDisplaySizeLock) {
- // Bootstrap the default logical display from the display manager.
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
- if (newDisplayInfo != null) {
- displayInfo.copyFrom(newDisplayInfo);
- }
- displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
- displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
- displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
- displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
- displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
- displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
- displayContent.mBaseDisplayRect.set(0, 0,
- displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
- }
+ displayContent.initializeDisplayBaseInfo();
}
}
}
@@ -8787,7 +8796,8 @@ private void setOverscanLocked(DisplayContent displayContent,
displayInfo.overscanBottom = bottom;
}
- mDisplaySettings.setOverscanLocked(displayInfo.uniqueId, left, top, right, bottom);
+ mDisplaySettings.setOverscanLocked(displayInfo.uniqueId, displayInfo.name, left, top,
+ right, bottom);
mDisplaySettings.writeSettingsLocked();
reconfigureDisplayLocked(displayContent);
@@ -10184,6 +10194,7 @@ private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMe
}
}
+ winAnimator.computeShownFrameLocked();
winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
}
@@ -11969,6 +11980,14 @@ public Object getWindowManagerLock() {
return mWindowMap;
}
+ @Override
+ public void setLiveLockscreenEdgeDetector(boolean enable) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ == PackageManager.PERMISSION_GRANTED) {
+ mPolicy.setLiveLockscreenEdgeDetector(enable);
+ }
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 0496592a41152..69488b163ac8c 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -79,6 +79,3 @@ $(shell mkdir -p $(OUT)/obj/SHARED_LIBRARIES/libtime_genoff_intermediates/)
$(shell touch $(OUT)/obj/SHARED_LIBRARIES/libtime_genoff_intermediates/export_includes)
endif
-ifeq ($(BOARD_HAVE_TIMERFD_POWEROFF_ALARM),true)
-LOCAL_CFLAGS += -DWITH_TIMERFD_POWEROFF_ALARM
-endif
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 80b89239d15e6..34d863cd94775 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -40,6 +40,8 @@
#include
#include
+#include
+
#if HAVE_QC_TIME_SERVICES
extern "C" {
#include
@@ -48,18 +50,16 @@ extern "C" {
namespace android {
-static const clockid_t android_alarm_to_clockid[] = {
+static const size_t N_ANDROID_TIMERFDS = ANDROID_ALARM_TYPE_COUNT + 1;
+static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
CLOCK_REALTIME_ALARM,
CLOCK_REALTIME,
CLOCK_BOOTTIME_ALARM,
CLOCK_BOOTTIME,
CLOCK_MONOTONIC,
-#ifdef WITH_TIMERFD_POWEROFF_ALARM
CLOCK_POWEROFF_ALARM,
-#endif
CLOCK_REALTIME,
};
-static const size_t N_ANDROID_TIMERFDS = sizeof(android_alarm_to_clockid)/sizeof(clockid_t);
/* to match the legacy alarm driver implementation, we need an extra
CLOCK_REALTIME fd which exists specifically to be canceled on RTC changes */
@@ -182,7 +182,7 @@ AlarmImplTimerFd::~AlarmImplTimerFd()
int AlarmImplTimerFd::set(int type, struct timespec *ts)
{
- if (type >= static_cast(N_ANDROID_TIMERFDS)) {
+ if (type > ANDROID_ALARM_TYPE_COUNT) {
errno = EINVAL;
return -1;
}
@@ -202,7 +202,7 @@ int AlarmImplTimerFd::set(int type, struct timespec *ts)
int AlarmImplTimerFd::clear(int type, struct timespec *ts)
{
- if (type >= static_cast(N_ANDROID_TIMERFDS)) {
+ if (type > ANDROID_ALARM_TYPE_COUNT) {
errno = EINVAL;
return -1;
}
@@ -283,7 +283,7 @@ int AlarmImplTimerFd::waitForAlarm()
uint64_t unused;
ssize_t err = read(fds[alarm_idx], &unused, sizeof(unused));
if (err < 0) {
- if (alarm_idx == (N_ANDROID_TIMERFDS - 1) && errno == ECANCELED) {
+ if (alarm_idx == ANDROID_ALARM_TYPE_COUNT && errno == ECANCELED) {
result |= ANDROID_ALARM_TIME_CHANGE_MASK;
} else {
return err;
@@ -380,14 +380,14 @@ static bool rtc_is_hctosys(unsigned int rtc_id)
static int wall_clock_rtc()
{
- DIR *dir = opendir(rtc_sysfs);
- if (!dir) {
+ std::unique_ptr dir(opendir(rtc_sysfs), closedir);
+ if (!dir.get()) {
ALOGE("failed to open %s: %s", rtc_sysfs, strerror(errno));
return -1;
}
struct dirent *dirent;
- while (errno = 0, dirent = readdir(dir)) {
+ while (errno = 0, dirent = readdir(dir.get())) {
unsigned int rtc_id;
int matched = sscanf(dirent->d_name, "rtc%u", &rtc_id);
@@ -424,6 +424,10 @@ static jlong init_timerfd()
for (size_t i = 0; i < N_ANDROID_TIMERFDS; i++) {
fds[i] = timerfd_create(android_alarm_to_clockid[i], 0);
+ if ((fds[i] < 0) && (android_alarm_to_clockid[i] == CLOCK_POWEROFF_ALARM)) {
+ ALOGV("timerfd does not support CLOCK_POWEROFF_ALARM, using CLOCK_REALTIME_ALARM instead");
+ fds[i] = timerfd_create(CLOCK_REALTIME_ALARM, 0);
+ }
if (fds[i] < 0) {
ALOGV("timerfd_create(%u) failed: %s", android_alarm_to_clockid[i],
strerror(errno));
@@ -455,7 +459,7 @@ static jlong init_timerfd()
/* 0 = disarmed; the timerfd doesn't need to be armed to get
RTC change notifications, just set up as cancelable */
- int err = timerfd_settime(fds[N_ANDROID_TIMERFDS - 1],
+ int err = timerfd_settime(fds[ANDROID_ALARM_TYPE_COUNT],
TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, NULL);
if (err < 0) {
ALOGV("timerfd_settime() failed: %s", strerror(errno));
diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
index 4ccfa56cd30cb..9b0393b44d727 100644
--- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp
+++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
@@ -84,7 +84,11 @@ namespace android {
if (fd < 0)
return 0;
- return get_block_device_size(fd);
+ const uint64_t size = get_block_device_size(fd);
+
+ close(fd);
+
+ return size;
}
static int com_android_server_PersistentDataBlockService_wipe(JNIEnv *env, jclass, jstring jpath) {
@@ -94,7 +98,11 @@ namespace android {
if (fd < 0)
return 0;
- return wipe_block_device(fd);
+ const int ret = wipe_block_device(fd);
+
+ close(fd);
+
+ return ret;
}
static JNINativeMethod sMethods[] = {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b2cb2ff81d90f..302d23a636f3f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4215,18 +4215,8 @@ public boolean requireSecureKeyguard(int userHandle) {
|| encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING) {
return true;
}
-
- // Keystore.isEmpty() requires system UID
- long token = Binder.clearCallingIdentity();
- try {
- if (!KeyStore.getInstance().isEmpty()) {
- return true;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- return false;
+ final int keyguardDisabledFeatures = getKeyguardDisabledFeatures(null, userHandle);
+ return (keyguardDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
}
// Returns the active device owner or null if there is no device owner.
diff --git a/services/java/com/android/server/AppsFailureReceiver.java b/services/java/com/android/server/AppsFailureReceiver.java
deleted file mode 100644
index e99b7a4eda8e7..0000000000000
--- a/services/java/com/android/server/AppsFailureReceiver.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2010, T-Mobile USA, Inc.
- * Copyright (C) 2015 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.server;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ThemeUtils;
-import android.content.res.ThemeChangeRequest;
-import android.content.res.ThemeChangeRequest.RequestType;
-import android.content.res.ThemeConfig;
-import android.content.res.ThemeManager;
-import android.os.SystemClock;
-
-import com.android.internal.R;
-
-public class AppsFailureReceiver extends BroadcastReceiver {
-
- private static final int FAILURES_THRESHOLD = 3;
- private static final int EXPIRATION_TIME_IN_MILLISECONDS = 30000; // 30 seconds
-
- private static final int THEME_RESET_NOTIFICATION_ID = 0x4641494C;
-
- private int mFailuresCount = 0;
- private long mStartTime = 0;
-
- // This function implements the following logic.
- // If after a theme was applied the number of application launch failures
- // at any moment was equal to FAILURES_THRESHOLD
- // in less than EXPIRATION_TIME_IN_MILLISECONDS
- // the default theme is applied unconditionally.
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_APP_FAILURE)) {
- long currentTime = SystemClock.uptimeMillis();
- String pkgName = intent.getStringExtra("package");
- if (currentTime - mStartTime > EXPIRATION_TIME_IN_MILLISECONDS) {
- // reset both the count and the timer
- mStartTime = currentTime;
- mFailuresCount = 0;
- }
- if (mFailuresCount <= FAILURES_THRESHOLD) {
- mFailuresCount++;
- if (mFailuresCount == FAILURES_THRESHOLD) {
- // let the theme manager take care of getting us back on the default theme
- ThemeManager tm =
- (ThemeManager) context.getSystemService(Context.THEME_SERVICE);
- final String themePkgName = ThemeConfig.SYSTEM_DEFAULT;
- ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder();
- builder.setOverlay(themePkgName)
- .setStatusBar(themePkgName)
- .setNavBar(themePkgName)
- .setIcons(themePkgName)
- .setFont(themePkgName)
- .setBootanimation(themePkgName)
- .setWallpaper(themePkgName)
- .setLockWallpaper(themePkgName)
- .setAlarm(themePkgName)
- .setNotification(themePkgName)
- .setRingtone(themePkgName)
- .setRequestType(RequestType.THEME_RESET);
- // Since we are resetting everything to the system theme, we can have the
- // theme service remove all per app themes without setting them explicitly :)
- tm.requestThemeChange(builder.build(), true);
- postThemeResetNotification(context);
- }
- }
- } else if (action.equals(Intent.ACTION_APP_FAILURE_RESET)
- || action.equals(ThemeUtils.ACTION_THEME_CHANGED)) {
- mFailuresCount = 0;
- mStartTime = SystemClock.uptimeMillis();
- } else if (action.equals(Intent.ACTION_PACKAGE_ADDED) ||
- action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
- mFailuresCount = 0;
- mStartTime = SystemClock.uptimeMillis();
- }
- }
-
- /**
- * Posts a notification to let the user know their theme was reset
- * @param context
- */
- private void postThemeResetNotification(Context context) {
- NotificationManager nm =
- (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- String title = context.getString(R.string.theme_reset_notification_title);
- String body = context.getString(R.string.theme_reset_notification_body);
- Notification notice = new Notification.Builder(context)
- .setAutoCancel(true)
- .setOngoing(false)
- .setContentTitle(title)
- .setContentText(body)
- .setStyle(new Notification.BigTextStyle().bigText(body))
- .setSmallIcon(android.R.drawable.stat_notify_error)
- .setWhen(System.currentTimeMillis())
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_MAX)
- .build();
- nm.notify(THEME_RESET_NOTIFICATION_ID, notice);
- }
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3146366854f14..d19f8acad238f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -18,6 +18,7 @@
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
+import android.app.IActivityManager;
import android.app.IAlarmManager;
import android.app.INotificationManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -25,16 +26,11 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ThemeUtils;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.database.ContentObserver;
-import android.database.Cursor;
-import android.content.res.ThemeConfig;
-import android.database.ContentObserver;
import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
@@ -47,7 +43,6 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.IMountService;
-import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
@@ -81,7 +76,6 @@
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.BackgroundDexOptService;
-import com.android.server.gesture.EdgeGestureService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
@@ -106,6 +100,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;
@@ -333,7 +330,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);
}
/**
@@ -462,8 +459,9 @@ 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(com.android.internal.R.array.config_externalCMServices);
+ String externalServer = context.getResources().getString(
+ org.cyanogenmod.platform.internal.R.string.config_externalSystemServer);
+ boolean disableAtlas = SystemProperties.getBoolean("config.disable_atlas", false);
try {
Slog.i(TAG, "Reading configuration...");
@@ -569,8 +567,6 @@ private void startOtherServices() {
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
GestureService gestureService = null;
- EdgeGestureService edgeGestureService = null;
- ThemeService themeService = null;
// Bring up services needed for UI.
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
@@ -625,10 +621,8 @@ private void startOtherServices() {
}
try {
- ActivityManagerNative.getDefault().showBootMessage(
- context.getResources().getText(
- com.android.internal.R.string.android_upgrading_starting_apps),
- false);
+ ActivityManagerNative.getDefault().updateBootProgress(
+ IActivityManager.BOOT_STAGE_STARTING_APPS, null, 0, 0, false);
} catch (RemoteException e) {
}
@@ -854,6 +848,11 @@ private void startOtherServices() {
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
+
+ if (context.getPackageManager().hasSystemFeature
+ (PackageManager.FEATURE_WATCH)) {
+ mSystemServiceManager.startService(ThermalObserver.class);
+ }
}
try {
@@ -961,7 +960,7 @@ private void startOtherServices() {
mSystemServiceManager.startService(DreamManagerService.class);
}
- if (!disableNonCoreServices) {
+ if (!disableNonCoreServices && !disableAtlas) {
try {
Slog.i(TAG, "Assets Atlas Service");
atlas = new AssetAtlasService(context);
@@ -1003,14 +1002,6 @@ private void startOtherServices() {
mSystemServiceManager.startService(TvInputManagerService.class);
}
- try {
- Slog.i(TAG, "Theme Service");
- themeService = new ThemeService(context);
- ServiceManager.addService(Context.THEME_SERVICE, themeService);
- } catch (Throwable e) {
- reportWtf("starting Theme Service", e);
- }
-
if (!disableNonCoreServices) {
try {
Slog.i(TAG, "Media Router Service");
@@ -1034,14 +1025,6 @@ private void startOtherServices() {
}
mSystemServiceManager.startService(LauncherAppsService.class);
-
- try {
- Slog.i(TAG, "EdgeGesture service");
- edgeGestureService = new EdgeGestureService(context, inputManager);
- ServiceManager.addService("edgegestureservice", edgeGestureService);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting EdgeGesture service", e);
- }
}
if (!disableNonCoreServices) {
@@ -1072,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...
@@ -1121,6 +1113,12 @@ private void startOtherServices() {
w.getDefaultDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
+ // The system context's theme may be configuration-dependent.
+ final Theme systemTheme = context.getTheme();
+ if (systemTheme.getChangingConfigurations() != 0) {
+ systemTheme.rebase();
+ }
+
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
@@ -1141,14 +1139,6 @@ private void startOtherServices() {
reportWtf("making Display Manager Service ready", e);
}
- if (edgeGestureService != null) {
- try {
- edgeGestureService.systemReady();
- } catch (Throwable e) {
- reportWtf("making EdgeGesture service ready", e);
- }
- }
-
if (gestureService != null) {
try {
gestureService.systemReady();
@@ -1157,16 +1147,6 @@ private void startOtherServices() {
}
}
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_APP_FAILURE);
- filter.addAction(Intent.ACTION_APP_FAILURE_RESET);
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(ThemeUtils.ACTION_THEME_CHANGED);
- filter.addCategory(Intent.CATEGORY_THEME_PACKAGE_INSTALLED_STATE_CHANGE);
- filter.addDataScheme("package");
- context.registerReceiver(new AppsFailureReceiver(), filter);
-
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
@@ -1187,7 +1167,6 @@ private void startOtherServices() {
final MediaRouterService mediaRouterF = mediaRouter;
final AudioService audioServiceF = audioService;
final MmsServiceBroker mmsServiceF = mmsService;
- final ThemeService themeServiceF = themeService;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -1210,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) {
@@ -1326,17 +1296,6 @@ public void run() {
} catch (Throwable e) {
reportWtf("Notifying MmsService running", e);
}
-
- try {
- // now that the system is up, apply default theme if applicable
- if (themeServiceF != null) themeServiceF.systemRunning();
- ThemeConfig themeConfig =
- ThemeConfig.getBootTheme(context.getContentResolver());
- String iconPkg = themeConfig.getIconPackPkgName();
- mPackageManagerService.updateIconMapping(iconPkg);
- } catch (Throwable e) {
- reportWtf("Icon Mapping failed", e);
- }
}
});
}
@@ -1348,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/java/com/android/server/gesture/EdgeGestureInputFilter.java b/services/java/com/android/server/gesture/EdgeGestureInputFilter.java
deleted file mode 100644
index c42b7d098b45d..0000000000000
--- a/services/java/com/android/server/gesture/EdgeGestureInputFilter.java
+++ /dev/null
@@ -1,539 +0,0 @@
-/*
- * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
- *
- * 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.server.gesture;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.util.Slog;
-import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.IInputFilter;
-import android.view.IInputFilterHost;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.MotionEvent;
-import android.view.WindowManagerPolicy;
-import android.view.MotionEvent.PointerCoords;
-import android.view.MotionEvent.PointerProperties;
-
-import com.android.internal.R;
-import com.android.internal.util.gesture.EdgeGesturePosition;
-import com.android.server.gesture.EdgeGestureTracker.OnActivationListener;
-
-import java.io.PrintWriter;
-
-/**
- * A simple input filter, that listens for edge swipe gestures in the motion event input
- * stream.
- *
- * There are 5 distinct states of this filter.
- * 1) LISTEN:
- * mTracker.active == false
- * All motion events are passed through. If a ACTION_DOWN within a gesture trigger area happen
- * switch to DETECTING.
- * 2) DETECTING:
- * mTracker.active == true
- * All events are buffered now, and the gesture is checked by mTracker. If mTracker rejects
- * the gesture (hopefully as fast as possible) all cached events will be flushed out and the
- * filter falls back to LISTEN.
- * If mTracker accepts the gesture, clear all cached events and go to LOCKED.
- * 3) LOCKED:
- * mTracker.active == false
- * All events will be cached until the state changes to SYNTHESIZE through a filter
- * unlock event. If there is a ACTION_UP, _CANCEL or any PointerId differently to the last
- * event seen when mTracker accepted the gesture, we flush all events and go to LISTEN.
- * 4) SYNTHESIZE:
- * The first motion event found will be turned into a ACTION_DOWN event, all previous events
- * will be discarded.
- * 5) POSTSYNTHESIZE:
- * mSyntheticDownTime != -1
- * All following events will have the down time set to the synthesized ACTION_DOWN event time
- * until an ACTION_UP or ACTION_CANCEL is encountered and the state is reset to LISTEN.
- * 6) DROP:
- * All following events will be discarded. If there is an ACTION_UP, _CANCEL
- * we go to LISTEN state.
- *
- * If you are reading this within Java Doc, you are doing something wrong ;)
- */
-public class EdgeGestureInputFilter implements IInputFilter {
- /* WARNING!! The IInputFilter interface is used directly, there is no Binder between this and
- * the InputDispatcher.
- * This is fine, because it prevents unnecessary parceling, but beware:
- * This means we are running on the dispatch or listener thread of the input dispatcher. Every
- * cycle we waste here adds to the overall input latency.
- */
- private static final String TAG = "EdgeGestureInputFilter";
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_INPUT = false;
- // TODO: Should be turned off in final commit
- private static final boolean SYSTRACE = false;
-
- private final Handler mHandler;
-
- private IInputFilterHost mHost = null; // dispatcher thread
-
- private static final class MotionEventInfo {
- private static final int MAX_POOL_SIZE = 16;
-
- private static final Object sLock = new Object();
- private static MotionEventInfo sPool;
- private static int sPoolSize;
-
- private boolean mInPool;
-
- public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
- synchronized (sLock) {
- MotionEventInfo info;
- if (sPoolSize > 0) {
- sPoolSize--;
- info = sPool;
- sPool = info.next;
- info.next = null;
- info.mInPool = false;
- } else {
- info = new MotionEventInfo();
- }
- info.initialize(event, policyFlags);
- return info;
- }
- }
-
- private void initialize(MotionEvent event, int policyFlags) {
- this.event = MotionEvent.obtain(event);
- this.policyFlags = policyFlags;
- cachedTimeMillis = SystemClock.uptimeMillis();
- }
-
- public void recycle() {
- synchronized (sLock) {
- if (mInPool) {
- throw new IllegalStateException("Already recycled.");
- }
- clear();
- if (sPoolSize < MAX_POOL_SIZE) {
- sPoolSize++;
- next = sPool;
- sPool = this;
- mInPool = true;
- }
- }
- }
-
- private void clear() {
- event.recycle();
- event = null;
- policyFlags = 0;
- }
-
- public MotionEventInfo next;
- public MotionEvent event;
- public int policyFlags;
- public long cachedTimeMillis;
- }
- private final Object mLock = new Object();
- private MotionEventInfo mMotionEventQueue; // guarded by mLock
- private MotionEventInfo mMotionEventQueueTail; // guarded by mLock
- /* DEBUG */
- private int mMotionEventQueueCountDebug; // guarded by mLock
-
- private int mDeviceId; // dispatcher only
- private enum State {
- LISTEN, DETECTING, LOCKED, SYNTHESIZE, POSTSYNTHESIZE, DROP;
- }
- private State mState = State.LISTEN; // guarded by mLock
- private EdgeGestureTracker mTracker; // guarded by mLock
- private volatile int mPositions; // written by handler / read by dispatcher
- private volatile int mSensitivity; // written by handler / read by dispatcher
-
- // only used by dispatcher
- private long mSyntheticDownTime = -1;
- private PointerCoords[] mTempPointerCoords = new PointerCoords[1];
- private PointerProperties[] mTempPointerProperties = new PointerProperties[1];
-
- public EdgeGestureInputFilter(Context context, Handler handler) {
- mHandler = handler;
-
- final Resources res = context.getResources();
- mTracker = new EdgeGestureTracker(res.getDimensionPixelSize(
- R.dimen.edge_gesture_trigger_thickness),
- res.getDimensionPixelSize(R.dimen.edge_gesture_trigger_distance),
- res.getDimensionPixelSize(R.dimen.edge_gesture_perpendicular_distance));
- mTracker.setOnActivationListener(new OnActivationListener() {
- public void onActivation(MotionEvent event, int touchX, int touchY, EdgeGesturePosition position) {
- // mLock is held by #processMotionEvent
- mHandler.obtainMessage(EdgeGestureService.MSG_EDGE_GESTURE_ACTIVATION,
- touchX, touchY, position).sendToTarget();
- mState = State.LOCKED;
- }
- });
- mTempPointerCoords[0] = new PointerCoords();
- mTempPointerProperties[0] = new PointerProperties();
- }
-
- // called from handler thread (lock taken)
- public void updateDisplay(Display display, DisplayInfo displayInfo) {
- synchronized (mLock) {
- mTracker.updateDisplay(display);
- }
- }
-
- // called from handler thread (lock taken)
- public void updatePositions(int positions) {
- mPositions = positions;
- }
-
- // called from handler thread (lock taken)
- public void updateSensitivity(int sensitivity) {
- mSensitivity = sensitivity;
- }
-
- // called from handler thread
- public boolean unlockFilter() {
- synchronized (mLock) {
- if (mState == State.LOCKED) {
- mState = State.SYNTHESIZE;
- return true;
- }
- }
- return false;
- }
-
- public boolean dropSequence() {
- synchronized (mLock) {
- if (mState == State.LOCKED) {
- mState = State.DROP;
- return true;
- }
- }
- return false;
- }
-
- /**
- * Called to enqueue the input event for filtering.
- * The event must be recycled after the input filter processed it.
- * This method is guaranteed to be non-reentrant.
- *
- * @see InputFilter#filterInputEvent(InputEvent, int)
- * @param event The input event to enqueue.
- */
- // called by the input dispatcher thread
- public void filterInputEvent(InputEvent event, int policyFlags) throws RemoteException {
- if (SYSTRACE) {
- Trace.traceBegin(Trace.TRACE_TAG_INPUT, "filterInputEvent");
- }
- try {
- if (((event.getSource() & InputDevice.SOURCE_TOUCHSCREEN)
- != InputDevice.SOURCE_TOUCHSCREEN)
- || !(event instanceof MotionEvent)) {
- sendInputEvent(event, policyFlags);
- return;
- }
- if (DEBUG_INPUT) {
- Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
- + Integer.toHexString(policyFlags));
- }
- MotionEvent motionEvent = (MotionEvent) event;
- final int deviceId = event.getDeviceId();
- if (deviceId != mDeviceId) {
- processDeviceSwitch(deviceId, motionEvent, policyFlags);
- } else {
- if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
- synchronized (mLock) {
- clearAndResetStateLocked(false, true);
- }
- }
- processMotionEvent(motionEvent, policyFlags);
- }
- } finally {
- event.recycle();
- if (SYSTRACE) {
- Trace.traceEnd(Trace.TRACE_TAG_INPUT);
- }
- }
- }
-
- private void processDeviceSwitch(int deviceId, MotionEvent motionEvent, int policyFlags) {
- if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mDeviceId = deviceId;
- synchronized (mLock) {
- clearAndResetStateLocked(true, false);
- processMotionEvent(motionEvent, policyFlags);
- }
- } else {
- sendInputEvent(motionEvent, policyFlags);
- }
- }
-
- private void processMotionEvent(MotionEvent motionEvent, int policyFlags) {
- final int action = motionEvent.getActionMasked();
-
- synchronized (mLock) {
- switch (mState) {
- case LISTEN:
- if (action == MotionEvent.ACTION_DOWN) {
- boolean hit = mPositions != 0
- && mTracker.start(motionEvent, mPositions, mSensitivity);
- if (DEBUG) Slog.d(TAG, "start:" + hit);
- if (hit) {
- // cache the down event
- cacheDelayedMotionEventLocked(motionEvent, policyFlags);
- mState = State.DETECTING;
- return;
- }
- }
- sendInputEvent(motionEvent, policyFlags);
- break;
- case DETECTING:
- cacheDelayedMotionEventLocked(motionEvent, policyFlags);
- if (action == MotionEvent.ACTION_MOVE) {
- if (mTracker.move(motionEvent)) {
- // return: the tracker is either detecting or triggered onActivation
- return;
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "move: reset!");
- }
- clearAndResetStateLocked(false, true);
- break;
- case LOCKED:
- cacheDelayedMotionEventLocked(motionEvent, policyFlags);
- if (action != MotionEvent.ACTION_MOVE) {
- clearAndResetStateLocked(false, true);
- }
- break;
- case SYNTHESIZE:
- if (action == MotionEvent.ACTION_MOVE) {
- clearDelayedMotionEventsLocked();
- sendSynthesizedMotionEventLocked(motionEvent, policyFlags);
- mState = State.POSTSYNTHESIZE;
- } else {
- // This is the case where a race condition caught us: We already
- // returned the handler thread that it is all right to call
- // #gainTouchFocus(), but apparently this was wrong, as the gesture
- // was canceled now.
- clearAndResetStateLocked(false, true);
- }
- break;
- case POSTSYNTHESIZE:
- motionEvent.setDownTime(mSyntheticDownTime);
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mState = State.LISTEN;
- mSyntheticDownTime = -1;
- }
- sendInputEvent(motionEvent, policyFlags);
- break;
- case DROP:
- if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- clearDelayedMotionEventsLocked();
- mState = State.LISTEN;
- }
- break;
- }
- }
- }
-
- private void clearAndResetStateLocked(boolean force, boolean shift) {
- // ignore soft reset in POSTSYNTHESIZE, because we need to tamper with
- // the event stream and going to LISTEN after an ACTION_UP anyway
- if (!force && (mState == State.POSTSYNTHESIZE)) {
- return;
- }
- switch (mState) {
- case LISTEN:
- // this is a nop
- break;
- case DETECTING:
- mTracker.reset();
- // intentionally no break here
- case LOCKED:
- case SYNTHESIZE:
- sendDelayedMotionEventsLocked(shift);
- break;
- case POSTSYNTHESIZE:
- // hard reset (this will break the event stream)
- Slog.w(TAG, "Quit POSTSYNTHESIZE without ACTION_UP from ACTION_DOWN at "
- + mSyntheticDownTime);
- mSyntheticDownTime = -1;
- break;
- }
- // if there are future events that need to be tampered with, goto POSTSYNTHESIZE
- mState = mSyntheticDownTime == -1 ? State.LISTEN : State.POSTSYNTHESIZE;
- }
-
- private void sendInputEvent(InputEvent event, int policyFlags) {
- try {
- mHost.sendInputEvent(event, policyFlags);
- } catch (RemoteException e) {
- /* ignore */
- }
- }
-
- private void cacheDelayedMotionEventLocked(MotionEvent event, int policyFlags) {
- MotionEventInfo info = MotionEventInfo.obtain(event, policyFlags);
- if (mMotionEventQueue == null) {
- mMotionEventQueue = info;
- } else {
- mMotionEventQueueTail.next = info;
- }
- mMotionEventQueueTail = info;
- mMotionEventQueueCountDebug++;
- if (SYSTRACE) {
- Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
- }
- }
-
- private void sendDelayedMotionEventsLocked(boolean shift) {
- while (mMotionEventQueue != null) {
- MotionEventInfo info = mMotionEventQueue;
- mMotionEventQueue = info.next;
-
- if (DEBUG) {
- Slog.d(TAG, "Replay event: " + info.event);
- }
- mMotionEventQueueCountDebug--;
- if (SYSTRACE) {
- Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
- }
- if (shift) {
- final long offset = SystemClock.uptimeMillis() - info.cachedTimeMillis;
- if (info.event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSyntheticDownTime = info.event.getDownTime() + offset;
- }
- sendMotionEventWithOffsetLocked(info.event, info.policyFlags, mSyntheticDownTime, offset);
- if (info.event.getActionMasked() == MotionEvent.ACTION_UP) {
- mSyntheticDownTime = -1;
- }
- } else {
- sendInputEvent(info.event, info.policyFlags);
- }
- info.recycle();
- }
- mMotionEventQueueTail = null;
- }
-
- private void clearDelayedMotionEventsLocked() {
- while (mMotionEventQueue != null) {
- MotionEventInfo next = mMotionEventQueue.next;
- mMotionEventQueue.recycle();
- mMotionEventQueue = next;
- }
- mMotionEventQueueTail = null;
- mMotionEventQueueCountDebug = 0;
- if (SYSTRACE) {
- Trace.traceCounter(Trace.TRACE_TAG_INPUT, "meq", mMotionEventQueueCountDebug);
- }
- }
-
- private void sendMotionEventWithOffsetLocked(MotionEvent event, int policyFlags,
- long downTime, long offset) {
- final int pointerCount = event.getPointerCount();
- PointerCoords[] coords = getTempPointerCoordsWithMinSizeLocked(pointerCount);
- PointerProperties[] properties = getTempPointerPropertiesWithMinSizeLocked(pointerCount);
- for (int i = 0; i < pointerCount; i++) {
- event.getPointerCoords(i, coords[i]);
- event.getPointerProperties(i, properties[i]);
- }
- final long eventTime = event.getEventTime() + offset;
- sendInputEvent(MotionEvent.obtain(downTime, eventTime, event.getAction(), pointerCount,
- properties, coords, event.getMetaState(), event.getButtonState(), 1.0f, 1.0f,
- event.getDeviceId(), event.getEdgeFlags(), event.getSource(), event.getFlags()),
- policyFlags);
- }
-
- private PointerCoords[] getTempPointerCoordsWithMinSizeLocked(int size) {
- final int oldSize = mTempPointerCoords.length;
- if (oldSize < size) {
- PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
- mTempPointerCoords = new PointerCoords[size];
- System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerCoords[i] = new PointerCoords();
- }
- return mTempPointerCoords;
- }
-
- private PointerProperties[] getTempPointerPropertiesWithMinSizeLocked(int size) {
- final int oldSize = mTempPointerProperties.length;
- if (oldSize < size) {
- PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
- mTempPointerProperties = new PointerProperties[size];
- System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0, oldSize);
- }
- for (int i = oldSize; i < size; i++) {
- mTempPointerProperties[i] = new PointerProperties();
- }
- return mTempPointerProperties;
- }
-
- private void sendSynthesizedMotionEventLocked(MotionEvent event, int policyFlags) {
- if (event.getPointerCount() == 1) {
- event.getPointerCoords(0, mTempPointerCoords[0]);
- event.getPointerProperties(0, mTempPointerProperties[0]);
- MotionEvent down = MotionEvent.obtain(event.getEventTime(), event.getEventTime(),
- MotionEvent.ACTION_DOWN, 1, mTempPointerProperties, mTempPointerCoords,
- event.getMetaState(), event.getButtonState(),
- 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
- event.getSource(), event.getFlags());
- Slog.d(TAG, "Synthesized event:" + down);
- sendInputEvent(down, policyFlags);
- mSyntheticDownTime = event.getEventTime();
- } else {
- Slog.w(TAG, "Could not synthesize MotionEvent, this will drop all following events!");
- }
- }
-
- // should never be called
- public IBinder asBinder() {
- throw new UnsupportedOperationException();
- }
-
- // called by the input dispatcher thread
- public void install(IInputFilterHost host) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "EdgeGesture input filter installed.");
- }
- mHost = host;
- synchronized (mLock) {
- clearAndResetStateLocked(true, false);
- }
- }
-
- // called by the input dispatcher thread
- public void uninstall() throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "EdgeGesture input filter uninstalled.");
- }
- }
-
- // called by a Binder thread
- public void dump(PrintWriter pw, String prefix) {
- synchronized (mLock) {
- pw.print(prefix);
- pw.println("mState=" + mState.name());
- pw.print(prefix);
- pw.println("mPositions=0x" + Integer.toHexString(mPositions));
- pw.print(prefix);
- pw.println("mQueue=" + mMotionEventQueueCountDebug + " items");
- }
- }
-}
diff --git a/services/java/com/android/server/gesture/EdgeGestureService.java b/services/java/com/android/server/gesture/EdgeGestureService.java
deleted file mode 100644
index 0581831869c77..0000000000000
--- a/services/java/com/android/server/gesture/EdgeGestureService.java
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
- *
- * 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.server.gesture;
-
-import static com.android.internal.util.gesture.EdgeServiceConstants.POSITION_MASK;
-import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_DEFAULT;
-import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_MASK;
-import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_NONE;
-import static com.android.internal.util.gesture.EdgeServiceConstants.SENSITIVITY_SHIFT;
-import static com.android.internal.util.gesture.EdgeServiceConstants.LONG_LIVING;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.service.gesture.IEdgeGestureActivationListener;
-import android.service.gesture.IEdgeGestureHostCallback;
-import android.service.gesture.IEdgeGestureService;
-import android.util.Slog;
-import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.WindowManager;
-
-import com.android.internal.util.gesture.EdgeGesturePosition;
-import com.android.server.gesture.EdgeGestureInputFilter;
-import com.android.server.input.InputManagerService;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A system service to track and handle edge swipe gestures. This service interacts with
- * the {@link InputManagerService} to do all the dirty work for listeners:
- *
Installing an input filter and listen for edge swipe gestures
- * Removing those gestures from the input stream
- * Transferring touch focus to new recipient
- */
-public class EdgeGestureService extends IEdgeGestureService.Stub {
- public static final String TAG = "EdgeGestureService";
- public static final boolean DEBUG = false;
- public static final boolean DEBUG_INPUT = false;
-
- public static final int MSG_EDGE_GESTURE_ACTIVATION = 32023;
- public static final int MSG_UPDATE_SERVICE = 32025;
-
- private final Context mContext;
- private final InputManagerService mInputManager;
-
- private final HandlerThread mHandlerThread = new HandlerThread("EdgeGestureHandler");
- private Handler mHandler;
-
- // Lock for mInputFilter, activations and listener related variables
- private final Object mLock = new Object();
- private EdgeGestureInputFilter mInputFilter;
-
- private int mGlobalPositions = 0;
- private int mGlobalSensitivity = 3;
-
- private final class EdgeGestureActivationListenerRecord extends IEdgeGestureHostCallback.Stub implements DeathRecipient {
- private boolean mActive;
-
- public EdgeGestureActivationListenerRecord(IEdgeGestureActivationListener listener) {
- this.listener = listener;
- this.positions = 0;
- }
-
- public void binderDied() {
- removeListenerRecord(this);
- }
-
- private void updateFlags(int flags) {
- this.positions = flags & POSITION_MASK;
- this.sensitivity = (flags & SENSITIVITY_MASK) >> SENSITIVITY_SHIFT;
- this.longLiving = (flags & LONG_LIVING) != 0;
- }
-
- private boolean eligibleForActivation(int positionFlag) {
- return (positions & positionFlag) != 0;
- }
-
- private boolean notifyEdgeGestureActivation(int touchX, int touchY, EdgeGesturePosition position) {
- if ((positions & position.FLAG) != 0) {
- try {
- mActive = true;
- listener.onEdgeGestureActivation(touchX, touchY, position.INDEX, 0);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify process, assuming it died.", e);
- mActive = false;
- binderDied();
- }
- }
- return mActive;
- }
-
- // called through Binder
- public boolean gainTouchFocus(IBinder windowToken) {
- if (DEBUG) {
- Slog.d(TAG, "Gain touch focus for " + windowToken);
- }
- if (mActive) {
- return mInputFilter.unlockFilter();
- }
- return false;
- }
-
- public boolean dropEventsUntilLift() {
- if (DEBUG) {
- Slog.d(TAG, "Will drop all next events till touch up");
- }
- if (mActive) {
- return mInputFilter.dropSequence();
- }
- return false;
- }
-
- // called through Binder
- public void restoreListenerState() throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "Restore listener state");
- }
- if (mActive) {
- mInputFilter.unlockFilter();
- mActive = false;
- synchronized (mLock) {
- // restore input filter state by updating
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
- }
-
- public boolean isActive() {
- return mActive;
- }
-
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix);
- pw.print("mPositions=0x" + Integer.toHexString(positions));
- pw.println(" mActive=" + mActive);
- pw.print(prefix);
- pw.println("mBinder=" + listener);
- }
-
- public int positions;
- public int sensitivity;
- public final IEdgeGestureActivationListener listener;
- public boolean longLiving = false;
- }
- private final List mEdgeGestureActivationListener =
- new ArrayList();
- // end of lock guarded variables
-
- private DisplayObserver mDisplayObserver;
-
- // called by system server
- public EdgeGestureService(Context context, InputManagerService inputManager) {
- mContext = context;
- mInputManager = inputManager;
- }
-
- // called by system server
- public void systemReady() {
- if (DEBUG) Slog.d(TAG, "Starting the edge gesture capture thread ...");
-
- synchronized (mLock) {
- mHandlerThread.start();
- mHandler = new H(mHandlerThread.getLooper());
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_FOREGROUND);
- android.os.Process.setCanSelfBackground(false);
- }
- });
- mDisplayObserver = new DisplayObserver(mContext, mHandler);
- // check if anyone registered during startup
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
-
-
- private void updateMonitoring() {
- synchronized(mLock) {
- mGlobalPositions = 0;
- mGlobalSensitivity = SENSITIVITY_NONE;
- boolean someLongLiving = false;
- int activePositions = 0;
- for (EdgeGestureActivationListenerRecord temp : mEdgeGestureActivationListener) {
- mGlobalPositions |= temp.positions;
- if (temp.isActive()) {
- activePositions |= temp.positions;
- }
- if (temp.sensitivity != SENSITIVITY_NONE) {
- mGlobalSensitivity = Math.max(mGlobalSensitivity, temp.sensitivity);
- }
- someLongLiving |= temp.longLiving;
- }
- boolean havePositions = mGlobalPositions != 0;
- mGlobalPositions &= ~activePositions;
- // if no special sensitivity is requested, we settle on DEFAULT
- if (mGlobalSensitivity == SENSITIVITY_NONE) {
- mGlobalSensitivity = SENSITIVITY_DEFAULT;
- }
-
- if (mInputFilter == null && havePositions) {
- enforceMonitoringLocked();
- } else if (mInputFilter != null && !havePositions && !someLongLiving) {
- shutdownMonitoringLocked();
- }
- }
- }
-
- private void enforceMonitoringLocked() {
- if (DEBUG) {
- Slog.d(TAG, "Attempting to start monitoring input events ...");
- }
- mInputFilter = new EdgeGestureInputFilter(mContext, mHandler);
- mInputManager.registerSecondaryInputFilter(mInputFilter);
- mDisplayObserver.observe();
- }
-
- private void shutdownMonitoringLocked() {
- if (DEBUG) {
- Slog.d(TAG, "Shutting down monitoring input events ...");
- }
- mDisplayObserver.unobserve();
- mInputManager.unregisterSecondaryInputFilter(mInputFilter);
- mInputFilter = null;
- }
-
- // called through Binder
- public IEdgeGestureHostCallback registerEdgeGestureActivationListener(IEdgeGestureActivationListener listener) {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.INJECT_EVENTS)
- != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: can't register from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
- return null;
- }
-
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
-
- EdgeGestureActivationListenerRecord record = null;
- synchronized(mLock) {
- record = findListenerRecordLocked(listener.asBinder());
- if (record == null) {
- record = new EdgeGestureActivationListenerRecord(listener);
- try {
- listener.asBinder().linkToDeath(record, 0);
- } catch (RemoteException e) {
- Slog.w(TAG, "Recipient died during registration pid=" + Binder.getCallingPid());
- return null;
- }
- mEdgeGestureActivationListener.add(record);
- }
- }
- return record;
- }
-
- // called through Binder
- public void updateEdgeGestureActivationListener(IBinder listener, int positionFlags) {
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
- synchronized(mLock) {
- EdgeGestureActivationListenerRecord record = findListenerRecordLocked(listener);
- if (record == null) {
- Slog.w(TAG, "Unknown listener on update listener. Register first?");
- throw new IllegalStateException("listener not registered");
- }
- record.updateFlags(positionFlags);
- // update input filter only when #systemReady() was called
- if (mHandler != null) {
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
- }
-
- private EdgeGestureActivationListenerRecord findListenerRecordLocked(IBinder listener) {
- for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
- if (record.listener.asBinder().equals(listener)) {
- return record;
- }
- }
- return null;
- }
-
- private void removeListenerRecord(EdgeGestureActivationListenerRecord record) {
- synchronized(mLock) {
- mEdgeGestureActivationListener.remove(record);
- // restore input filter state by updating
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
-
- // called by handler thread
- private boolean propagateActivation(int touchX, int touchY, EdgeGesturePosition position) {
- synchronized(mLock) {
- EdgeGestureActivationListenerRecord target = null;
- for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
- if (record.eligibleForActivation(position.FLAG)) {
- target = record;
- break;
- }
- }
- // NOTE: We can do this here because the #onGestureActivation() is a oneway
- // Binder call. This means we do not block with holding the mListenerLock!!!
- // If this ever change, this needs to be adjusted and if you don't know what
- // this means, you should probably not mess around with this code, anyway.
- if (target != null && !target.notifyEdgeGestureActivation(touchX, touchY, position)) {
- target = null;
- }
- return target != null;
- }
- }
-
- private final class H extends Handler {
- public H(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message m) {
- switch (m.what) {
- case MSG_EDGE_GESTURE_ACTIVATION:
- if (DEBUG) {
- Slog.d(TAG, "Activating edge gesture on " + m.obj.toString());
- }
- // Since input filter runs asynchronously to us, double activation may happen
- // theoretically. Take the safe route here.
- removeMessages(MSG_EDGE_GESTURE_ACTIVATION);
- if (propagateActivation(m.arg1, m.arg2, (EdgeGesturePosition) m.obj)) {
- // switch off activated positions
- updateMonitoring();
- updateServiceHandler(mGlobalPositions, mGlobalSensitivity);
- }
- break;
- case MSG_UPDATE_SERVICE:
- updateMonitoring();
- if (DEBUG) {
- Slog.d(TAG, "Updating positions 0x" + Integer.toHexString(mGlobalPositions)
- + " sensitivity: " + mGlobalSensitivity);
- }
- updateServiceHandler(mGlobalPositions, mGlobalSensitivity);
- break;
- }
- }
-
- private void updateServiceHandler(int positions, int sensitivity) {
- synchronized (mLock) {
- if (mInputFilter != null) {
- mInputFilter.updatePositions(positions);
- mInputFilter.updateSensitivity(sensitivity);
- }
- }
- }
- }
-
- private final class DisplayObserver implements DisplayListener {
- private final Handler mHandler;
- private final DisplayManager mDisplayManager;
-
- private final Display mDefaultDisplay;
- private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
-
- public DisplayObserver(Context context, Handler handler) {
- mHandler = handler;
- mDisplayManager = (DisplayManager) context.getSystemService(
- Context.DISPLAY_SERVICE);
- final WindowManager windowManager = (WindowManager) context.getSystemService(
- Context.WINDOW_SERVICE);
-
- mDefaultDisplay = windowManager.getDefaultDisplay();
- updateDisplayInfo();
- }
-
- private void updateDisplayInfo() {
- if (DEBUG) {
- Slog.d(TAG, "Updating display information ...");
- }
- if (mDefaultDisplay.getDisplayInfo(mDefaultDisplayInfo)) {
- synchronized (mLock) {
- if (mInputFilter != null) {
- mInputFilter.updateDisplay(mDefaultDisplay, mDefaultDisplayInfo);
- }
- }
- } else {
- Slog.e(TAG, "Default display is not valid.");
- }
- }
-
- public void observe() {
- mDisplayManager.registerDisplayListener(this, mHandler);
- updateDisplayInfo();
- }
-
- public void unobserve() {
- mDisplayManager.unregisterDisplayListener(this);
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- /* do noting */
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- /* do nothing */
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- updateDisplayInfo();
- }
- }
-
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- // let's log all exceptions we do not know about.
- if (!(e instanceof IllegalArgumentException || e instanceof IllegalStateException)) {
- Slog.e(TAG, "EdgeGestureService crashed: ", e);
- }
- throw e;
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump EdgeGestureService from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- pw.println("EDGE GESTURE SERVICE (dumpsys edgegestureservice)\n");
- synchronized(mLock) {
- pw.println(" mInputFilter=" + mInputFilter);
- if (mInputFilter != null) {
- mInputFilter.dump(pw, " ");
- }
- pw.println(" mGlobalPositions=0x" + Integer.toHexString(mGlobalPositions));
- pw.println(" mGlobalSensitivity=" + mGlobalSensitivity);
- int i = 0;
- for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
- if (record.isActive()) {
- pw.println(" Active record: #" + (i + 1));
- }
- }
- i = 0;
- for (EdgeGestureActivationListenerRecord record : mEdgeGestureActivationListener) {
- pw.println(" Listener #" + i + ":");
- record.dump(pw, " ");
- i++;
- }
- }
- }
-}
diff --git a/services/java/com/android/server/gesture/EdgeGestureTracker.java b/services/java/com/android/server/gesture/EdgeGestureTracker.java
deleted file mode 100644
index 17cd95eda0d0b..0000000000000
--- a/services/java/com/android/server/gesture/EdgeGestureTracker.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2013 The CyanogenMod Project (Jens Doll)
- *
- * 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.server.gesture;
-
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.view.Display;
-import android.view.MotionEvent;
-
-import com.android.internal.util.gesture.EdgeGesturePosition;
-import com.android.internal.util.gesture.EdgeServiceConstants;
-
-/**
- * A simple {@link MotionEvent} tracker class. The main aim of this tracker is to
- * reject gestures as fast as possible, so there is only a small amount of events
- * that will be delayed.
- */
-public class EdgeGestureTracker {
- public final static String TAG = "EdgeGestureTracker";
- public final static boolean DEBUG = false;
-
- public final static long TRIGGER_TIME_MS = 140;
- public final static int PIXEL_SWIPE_OFFTAKE_SLOP = 2;
-
- private final int mBaseThickness;
- private final int mBaseTriggerDistance;
- private final int mBasePerpendicularDistance;
-
- private int mThickness;
- private int mTriggerDistance;
- private int mPerpendicularDistance;
- private int mGracePeriodDistance;
- private long mTimeOut;
-
- private int mDisplayWidth;
- private int mDisplayHeight;
-
- private boolean mActive;
- private EdgeGesturePosition mPosition;
- private long mDownTime;
- private int mInitialX;
- private int mInitialY;
- private int mOffTake;
- private int mGracePeriod;
-
- public interface OnActivationListener {
- public void onActivation(MotionEvent event, int touchX, int touchY, EdgeGesturePosition position);
- }
- private OnActivationListener mActivationListener;
-
- public EdgeGestureTracker(int thickness, int distance, int perpendicular) {
- if (DEBUG) {
- Slog.d(TAG, "init: " + thickness + "," + distance);
- }
- mBaseThickness = thickness;
- mBaseTriggerDistance = distance;
- mBasePerpendicularDistance = perpendicular;
- setSensitivity(0);
- }
-
- private void setSensitivity(int sensitivity) {
- float factor = 0.0f;
- if (sensitivity >= 1) {
- factor = (sensitivity - 1) / 4.0f;
- }
- if (DEBUG) {
- Slog.d(TAG, "sensitivity: " + sensitivity + " => factor:" + factor);
- }
- // default values (without overlay):
- // 140ms ... 210ms
- mTimeOut = (long) (TRIGGER_TIME_MS * (factor + 1.0f));
- // 12dp ... 18dp
- mThickness = (int) (mBaseThickness * (factor + 1.0f));
- // 12dp ... 6dp
- mTriggerDistance = (int) (mBaseTriggerDistance * (1.0f - factor));
- mPerpendicularDistance = (int) (mBasePerpendicularDistance * (1.0f - factor));
- mGracePeriodDistance = (int) (mThickness / 3.0f);
- }
-
- public void setOnActivationListener(OnActivationListener listener) {
- mActivationListener = listener;
- }
-
- public void reset() {
- mActive = false;
- }
-
- public void updateDisplay(Display display) {
- Point outSize = new Point(0,0);
- display.getRealSize(outSize);
- mDisplayWidth = outSize.x;
- mDisplayHeight = outSize.y;
- if (DEBUG) {
- Slog.d(TAG, "new display: " + mDisplayWidth + "," + mDisplayHeight);
- }
- }
-
- public boolean start(MotionEvent motionEvent, int positions, int sensitivity) {
- final boolean unrestricted = (positions & EdgeServiceConstants.UNRESTRICTED) != 0;
- final int x = (int) motionEvent.getX();
- final float fx = motionEvent.getX() / mDisplayWidth;
- final int y = (int) motionEvent.getY();
- final float fy = motionEvent.getY() / mDisplayHeight;
-
- // calculate trigger geometry based on sensitivity
- setSensitivity(sensitivity);
-
- if ((positions & EdgeGesturePosition.LEFT.FLAG) != 0) {
- if (x < mThickness && (unrestricted || (fy > 0.1f && fy < 0.9f))) {
- startWithPosition(motionEvent, EdgeGesturePosition.LEFT);
- return true;
- }
- }
- if ((positions & EdgeGesturePosition.BOTTOM.FLAG) != 0) {
- if (y > mDisplayHeight - mThickness && (unrestricted || (fx > 0.1f && fx < 0.9f))) {
- startWithPosition(motionEvent, EdgeGesturePosition.BOTTOM);
- return true;
- }
- }
- if ((positions & EdgeGesturePosition.RIGHT.FLAG) != 0) {
- if (x > mDisplayWidth - mThickness && (unrestricted || (fy > 0.1f && fy < 0.9f))) {
- startWithPosition(motionEvent, EdgeGesturePosition.RIGHT);
- return true;
- }
- }
- if ((positions & EdgeGesturePosition.TOP.FLAG) != 0) {
- if (y < mThickness && (unrestricted || (fx > 0.1f && fx < 0.9f))) {
- startWithPosition(motionEvent, EdgeGesturePosition.TOP);
- return true;
- }
- }
- return false;
- }
-
- private void startWithPosition(MotionEvent motionEvent, EdgeGesturePosition position) {
- if (DEBUG) {
- Slog.d(TAG, "start tracking from " + position.name());
- }
-
- mDownTime = motionEvent.getDownTime();
- this.mPosition = position;
- mInitialX = (int) motionEvent.getX();
- mInitialY = (int) motionEvent.getY();
- switch (position) {
- case LEFT:
- mGracePeriod = mGracePeriodDistance;
- mOffTake = mInitialX - PIXEL_SWIPE_OFFTAKE_SLOP;
- break;
- case BOTTOM:
- mOffTake = mInitialY + PIXEL_SWIPE_OFFTAKE_SLOP;
- break;
- case RIGHT:
- mGracePeriod = mDisplayWidth - mGracePeriodDistance;
- mOffTake = mInitialX + PIXEL_SWIPE_OFFTAKE_SLOP;
- break;
- case TOP:
- mOffTake = mInitialY - PIXEL_SWIPE_OFFTAKE_SLOP;
- break;
- }
- mActive = true;
- }
-
- public boolean move(MotionEvent motionEvent) {
- if (!mActive || motionEvent.getEventTime() - mDownTime > mTimeOut) {
- Slog.d(TAG, "edge gesture timeout: " + (motionEvent.getEventTime() - mDownTime));
- mActive = false;
- return false;
- }
-
- final int x = (int) motionEvent.getX();
- final int y = (int) motionEvent.getY();
- final int deltaX = x - mInitialX;
- final int deltaY = y - mInitialY;
-
- if (DEBUG) {
- Slog.d(TAG, "move at " + x + "," + y + " " + deltaX + "," + deltaY);
- }
-
- boolean loaded = false;
- switch (mPosition) {
- case LEFT:
- if (x < mGracePeriod) {
- mInitialY = y;
- }
- if (deltaY < mPerpendicularDistance && deltaY > -mPerpendicularDistance
- && x >= mOffTake) {
- if (deltaX < mTriggerDistance) {
- mOffTake = x - PIXEL_SWIPE_OFFTAKE_SLOP;
- return true;
- }
- loaded = true;
- }
- break;
- case BOTTOM:
- if (deltaX < mPerpendicularDistance && deltaX > -mPerpendicularDistance
- && y <= mOffTake) {
- if (deltaY > -mTriggerDistance) {
- mOffTake = y + PIXEL_SWIPE_OFFTAKE_SLOP;
- return true;
- }
- loaded = true;
- }
- break;
- case RIGHT:
- if (x > mGracePeriod) {
- mInitialY = y;
- }
- if (deltaY < mPerpendicularDistance && deltaY > -mPerpendicularDistance
- && x <= mOffTake) {
- if (deltaX > -mTriggerDistance) {
- mOffTake = x + PIXEL_SWIPE_OFFTAKE_SLOP;
- return true;
- }
- loaded = true;
- }
- break;
- case TOP:
- if (deltaX < mPerpendicularDistance && deltaX > -mPerpendicularDistance
- && y >= mOffTake) {
- if (deltaY < mTriggerDistance) {
- mOffTake = y - PIXEL_SWIPE_OFFTAKE_SLOP;
- return true;
- }
- loaded = true;
- }
- break;
- }
- mActive = false;
- if (loaded && mActivationListener != null) {
- if (DEBUG) {
- Slog.d(TAG, "activate at " + x + "," + y + " " + mPosition + " within "
- + (SystemClock.uptimeMillis() - mDownTime) + "ms");
- }
- mActivationListener.onActivation(motionEvent, x, y, mPosition);
- }
- return loaded;
- }
-}
\ No newline at end of file
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 8927bfa25654e..f97df83706fff 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -602,7 +602,12 @@ protected static void addTlvEnd(ByteBuffer buf) {
protected void addCommonClientTlvs(ByteBuffer buf) {
addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
addTlv(buf, DHCP_VENDOR_CLASS_ID, "android-dhcp-" + Build.VERSION.RELEASE);
- addTlv(buf, DHCP_HOST_NAME, SystemProperties.get("net.hostname"));
+
+ /* the default 'android-dhcp' is there to make sure the hostname is
+ * never empty, because the DHCP standard forbids it (RFC2132, section
+ * 3.14) and certain DHCP forwarders and servers ignore such malformed
+ * requests */
+ addTlv(buf, DHCP_HOST_NAME, SystemProperties.get("net.hostname", "android-dhcp"));
}
/**
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 993faa9379232..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;
@@ -263,7 +264,7 @@ public void testReadKeySetSettings()
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
verifyKeySetMetaData(settings);
}
@@ -275,11 +276,11 @@ public void testWriteKeySetSettings()
writeOldFiles();
createUserManagerServiceRef();
Settings settings = new Settings(getContext().getFilesDir(), new Object());
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
/* write out, read back in and verify the same */
settings.writeLPr();
- assertEquals(true, settings.readLPw(null, null, 0, false));
+ assertEquals(true, settings.readLPw(null, null, 0, false, null));
verifyKeySetMetaData(settings);
}
@@ -357,7 +358,7 @@ public void testEnableDisable() {
// Checks if a package that is locked to a different region is rejected
// from being installed
public void testPrebundledDifferentRegionReject() {
- Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ Settings settings = new Settings(getContext().getFilesDir());
String expectedPackageNeededForRegion = "org.cyanogenmod.restricted.package";
Resources resources = Mockito.mock(Resources.class);
String[] regionRestrictedPackages = new String[] {
@@ -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));
}
@@ -373,7 +374,7 @@ public void testPrebundledDifferentRegionReject() {
// This also covers the test for a package that needs to be installed on a
// non region locked device
public void testPrebundledMatchingRegionAccept() {
- Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ Settings settings = new Settings(getContext().getFilesDir());
String expectedPackageNeededForRegion = "org.cyanogenmod.restricted.package";
Resources resources = Mockito.mock(Resources.class);
String[] regionLockedPackages = new String[] {
@@ -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/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 54d9cd98f32b3..583bac2fedb64 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -123,6 +123,7 @@ public class UsageStatsService extends SystemService implements
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
static final int MSG_PAROLE_STATE_CHANGED = 9;
+ static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
private final Object mLock = new Object();
Handler mHandler;
@@ -144,8 +145,10 @@ public class UsageStatsService extends SystemService implements
private boolean mScreenOn;
private long mLastAppIdleParoledTime;
+ private volatile boolean mPendingOneTimeCheckIdleStates;
+
long mScreenOnTime;
- long mScreenOnSystemTimeSnapshot;
+ long mLastScreenOnEventRealtime;
@GuardedBy("mLock")
private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
@@ -188,6 +191,8 @@ public void onStart() {
synchronized (mLock) {
cleanUpRemovedUsersLocked();
+ mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
+ mScreenOnTime = readScreenOnTimeLocked();
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -214,14 +219,14 @@ public void onBootPhase(int phase) {
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
- mScreenOnSystemTimeSnapshot = System.currentTimeMillis();
- synchronized (this) {
- mScreenOnTime = readScreenOnTimeLocked();
- }
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ mDisplayManager.registerDisplayListener(mDisplayListener, null);
synchronized (this) {
updateDisplayLocked();
}
+
+ if (mPendingOneTimeCheckIdleStates) {
+ postOneTimeCheckIdleStates();
+ }
} else if (phase == PHASE_BOOT_COMPLETED) {
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
}
@@ -280,6 +285,16 @@ public void onStatsUpdated() {
mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
}
+ @Override
+ public void onStatsReloaded() {
+ postOneTimeCheckIdleStates();
+ }
+
+ @Override
+ public long getAppIdleRollingWindowDurationMillis() {
+ return mAppIdleWallclockThresholdMillis * 2;
+ }
+
private void cleanUpRemovedUsersLocked() {
final List users = mUserManager.getUsers(true);
if (users == null || users.size() == 0) {
@@ -354,6 +369,20 @@ void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
+ /**
+ * We send a different message to check idle states once, otherwise we would end up
+ * scheduling a series of repeating checkIdleStates each time we fired off one.
+ */
+ void postOneTimeCheckIdleStates() {
+ if (mDeviceIdleController == null) {
+ // Not booted yet; wait for it!
+ mPendingOneTimeCheckIdleStates = true;
+ } else {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ mPendingOneTimeCheckIdleStates = false;
+ }
+ }
+
/** Check all running users' or specified user's apps to see if they enter an idle state. */
void checkIdleStates(int checkUserId) {
if (!mAppIdleEnabled) {
@@ -380,7 +409,7 @@ void checkIdleStates(int checkUserId) {
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
timeNow);
final int packageCount = packages.size();
@@ -396,8 +425,6 @@ void checkIdleStates(int checkUserId) {
}
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
- mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -437,21 +464,21 @@ void updateDisplayLocked() {
if (screenOn == mScreenOn) return;
mScreenOn = screenOn;
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
if (mScreenOn) {
- mScreenOnSystemTimeSnapshot = now;
+ mLastScreenOnEventRealtime = now;
} else {
- mScreenOnTime += now - mScreenOnSystemTimeSnapshot;
+ mScreenOnTime += now - mLastScreenOnEventRealtime;
writeScreenOnTimeLocked(mScreenOnTime);
}
}
- private long getScreenOnTimeLocked(long now) {
+ long getScreenOnTimeLocked() {
+ long screenOnTime = mScreenOnTime;
if (mScreenOn) {
- return now - mScreenOnSystemTimeSnapshot + mScreenOnTime;
- } else {
- return mScreenOnTime;
+ screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
}
+ return screenOnTime;
}
private File getScreenOnTimeFile() {
@@ -521,7 +548,7 @@ private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId,
if (service == null) {
service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
- service.init(currentTimeMillis, getScreenOnTimeLocked(currentTimeMillis));
+ service.init(currentTimeMillis, getScreenOnTimeLocked());
mUserState.put(userId, service);
}
return service;
@@ -534,20 +561,15 @@ private long checkAndGetTimeLocked() {
final long actualSystemTime = System.currentTimeMillis();
final long actualRealtime = SystemClock.elapsedRealtime();
final long expectedSystemTime = (actualRealtime - mRealTimeSnapshot) + mSystemTimeSnapshot;
- boolean resetBeginIdleTime = false;
- if (Math.abs(actualSystemTime - expectedSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
+ final long diffSystemTime = actualSystemTime - expectedSystemTime;
+ if (Math.abs(diffSystemTime) > TIME_CHANGE_THRESHOLD_MILLIS) {
// The time has changed.
-
- // Check if it's severe enough a change to reset screenOnTime
- if (Math.abs(actualSystemTime - expectedSystemTime) > mAppIdleDurationMillis) {
- mScreenOnSystemTimeSnapshot = actualSystemTime;
- mScreenOnTime = 0;
- resetBeginIdleTime = true;
- }
+ Slog.i(TAG, "Time changed in UsageStats by " + (diffSystemTime / 1000) + " seconds");
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, resetBeginIdleTime);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
+ false);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
@@ -579,7 +601,7 @@ void shutdown() {
void reportEvent(UsageEvents.Event event, int userId) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
convertToSystemTimeLocked(event);
final UserUsageStatsService service =
@@ -595,7 +617,6 @@ void reportEvent(UsageEvents.Event event, int userId) {
|| event.mEventType == Event.SYSTEM_INTERACTION
|| event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
@@ -636,7 +657,7 @@ void reportContentProviderUsage(String authority, String providerPkgName, int us
void forceIdleState(String packageName, int userId, boolean idle) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ final long screenOnTime = getScreenOnTimeLocked();
final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
final UserUsageStatsService service =
@@ -650,7 +671,6 @@ void forceIdleState(String packageName, int userId, boolean idle) {
timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
- // Slog.d(TAG, "Informing listeners of out-of-idle " + packageName);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
if (!idle) {
@@ -789,7 +809,7 @@ boolean isAppIdleFiltered(String packageName, int uidForAppId, int userId, long
timeNow = checkAndGetTimeLocked();
}
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
userService, timeNow, screenOnTime);
@@ -858,7 +878,7 @@ int[] getIdleUidsForUser(int userId) {
synchronized (mLock) {
timeNow = checkAndGetTimeLocked();
userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked(timeNow);
+ screenOnTime = getScreenOnTimeLocked();
}
List apps;
@@ -980,7 +1000,7 @@ private void flushToDiskLocked() {
*/
void dump(String[] args, PrintWriter pw) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
+ final long screenOnTime = getScreenOnTimeLocked();
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
ArraySet argSet = new ArraySet<>();
argSet.addAll(Arrays.asList(args));
@@ -1001,7 +1021,11 @@ void dump(String[] args, PrintWriter pw) {
}
idpw.decreaseIndent();
}
- pw.println("Screen On Timebase:" + mScreenOnTime);
+ pw.print("Screen On Timebase: ");
+ pw.print(screenOnTime);
+ pw.print(" (");
+ TimeUtils.formatDuration(screenOnTime, pw);
+ pw.println(")");
pw.println();
pw.println("Settings:");
@@ -1035,8 +1059,8 @@ void dump(String[] args, PrintWriter pw) {
pw.println();
pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
pw.println();
- pw.print("mScreenOnSystemTimeSnapshot=");
- TimeUtils.formatDuration(mScreenOnSystemTimeSnapshot, pw);
+ pw.print("mLastScreenOnEventRealtime=");
+ TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
pw.println();
}
}
@@ -1071,6 +1095,14 @@ public void handleMessage(Message msg) {
case MSG_CHECK_IDLE_STATES:
checkIdleStates(msg.arg1);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ break;
+
+ case MSG_ONE_TIME_CHECK_IDLE_STATES:
+ mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ checkIdleStates(UserHandle.USER_ALL);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -1106,7 +1138,13 @@ public void handleMessage(Message msg) {
* Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}.
*/
private class SettingsObserver extends ContentObserver {
- private static final String KEY_IDLE_DURATION = "idle_duration";
+ /**
+ * This flag has been used to disable app idle on older builds with bug b/26355386.
+ */
+ @Deprecated
+ private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
+
+ private static final String KEY_IDLE_DURATION = "idle_duration2";
private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
private static final String KEY_PAROLE_INTERVAL = "parole_interval";
private static final String KEY_PAROLE_DURATION = "parole_duration";
@@ -1125,7 +1163,7 @@ void registerObserver() {
@Override
public void onChange(boolean selfChange) {
updateSettings();
- postCheckIdleStates(UserHandle.USER_ALL);
+ postOneTimeCheckIdleStates();
}
void updateSettings() {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b07b8153279d2..a9f7ae0107acf 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -59,6 +59,7 @@ class UserUsageStatsService {
private final Context mContext;
private final UsageStatsDatabase mDatabase;
private final IntervalStats[] mCurrentStats;
+ private IntervalStats mAppIdleRollingWindow;
private boolean mStatsChanged = false;
private final UnixCalendar mDailyExpiryDate;
private final StatsUpdatedListener mListener;
@@ -67,6 +68,8 @@ class UserUsageStatsService {
interface StatsUpdatedListener {
void onStatsUpdated();
+ void onStatsReloaded();
+ long getAppIdleRollingWindowDurationMillis();
}
UserUsageStatsService(Context context, int userId, File usageStatsDir,
@@ -134,6 +137,8 @@ void init(final long currentTimeMillis, final long deviceUsageTime) {
stat.updateConfigurationStats(null, stat.lastTimeSaved);
}
+ refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
+
if (mDatabase.isNewUpdate()) {
initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
mDatabase.isFirstUpdate());
@@ -159,18 +164,23 @@ && getBeginIdleTime(packageName) == -1) {
for (IntervalStats stats : mCurrentStats) {
stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
stats.updateBeginIdleTime(packageName, deviceUsageTime);
- mStatsChanged = true;
}
+ mAppIdleRollingWindow.update(packageName, currentTimeMillis,
+ Event.SYSTEM_INTERACTION);
+ mAppIdleRollingWindow.updateBeginIdleTime(packageName, deviceUsageTime);
+ mStatsChanged = true;
}
}
// Persist the new OTA-related access stats.
persistActiveStats();
}
- void onTimeChanged(long oldTime, long newTime, boolean resetBeginIdleTime) {
+ void onTimeChanged(long oldTime, long newTime, long deviceUsageTime,
+ boolean resetBeginIdleTime) {
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
loadActiveStats(newTime, /* force= */ true, resetBeginIdleTime);
+ refreshAppIdleRollingWindow(newTime, deviceUsageTime);
}
void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -182,7 +192,7 @@ void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
// Need to rollover
- rolloverStats(event.mTimeStamp);
+ rolloverStats(event.mTimeStamp, deviceUsageTime);
}
final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
@@ -212,6 +222,11 @@ void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
}
}
+ if (event.mEventType != Event.CONFIGURATION_CHANGE) {
+ mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime);
+ }
+
notifyStatsChanged();
}
@@ -223,6 +238,7 @@ void setBeginIdleTime(String packageName, long beginIdleTime) {
for (IntervalStats stats : mCurrentStats) {
stats.updateBeginIdleTime(packageName, beginIdleTime);
}
+ mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime);
notifyStatsChanged();
}
@@ -230,6 +246,7 @@ void setSystemLastUsedTime(String packageName, long lastUsedTime) {
for (IntervalStats stats : mCurrentStats) {
stats.updateSystemLastUsedTime(packageName, lastUsedTime);
}
+ mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime);
notifyStatsChanged();
}
@@ -388,9 +405,8 @@ public void combine(IntervalStats stats, boolean mutable,
}
long getBeginIdleTime(String packageName) {
- final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
- if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+ if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
return -1;
} else {
return packageUsage.getBeginIdleTime();
@@ -398,9 +414,8 @@ long getBeginIdleTime(String packageName) {
}
long getSystemLastUsedTime(String packageName) {
- final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
- if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+ if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
return -1;
} else {
return packageUsage.getLastTimeSystemUsed();
@@ -421,7 +436,7 @@ void persistActiveStats() {
}
}
- private void rolloverStats(final long currentTimeMillis) {
+ private void rolloverStats(final long currentTimeMillis, final long deviceUsageTime) {
final long startTime = SystemClock.elapsedRealtime();
Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
@@ -462,6 +477,8 @@ private void rolloverStats(final long currentTimeMillis) {
}
persistActiveStats();
+ refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
+
final long totalTime = SystemClock.elapsedRealtime() - startTime;
Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
+ " milliseconds");
@@ -521,6 +538,7 @@ private void loadActiveStats(final long currentTimeMillis, boolean force,
}
}
}
+
mStatsChanged = false;
mDailyExpiryDate.setTimeInMillis(currentTimeMillis);
mDailyExpiryDate.addDays(1);
@@ -528,6 +546,74 @@ private void loadActiveStats(final long currentTimeMillis, boolean force,
Slog.i(TAG, mLogPrefix + "Rollover scheduled @ " +
sDateFormat.format(mDailyExpiryDate.getTimeInMillis()) + "(" +
tempCal.getTimeInMillis() + ")");
+
+ // Tell the listener that the stats reloaded, which may have changed idle states.
+ mListener.onStatsReloaded();
+ }
+
+ private static void mergePackageStats(IntervalStats dst, IntervalStats src,
+ final long deviceUsageTime) {
+ dst.endTime = Math.max(dst.endTime, src.endTime);
+
+ final int srcPackageCount = src.packageStats.size();
+ for (int i = 0; i < srcPackageCount; i++) {
+ final String packageName = src.packageStats.keyAt(i);
+ final UsageStats srcStats = src.packageStats.valueAt(i);
+ UsageStats dstStats = dst.packageStats.get(packageName);
+ if (dstStats == null) {
+ dstStats = new UsageStats(srcStats);
+ dst.packageStats.put(packageName, dstStats);
+ } else {
+ dstStats.add(src.packageStats.valueAt(i));
+ }
+
+ // App idle times can not begin in the future. This happens if we had a time change.
+ if (dstStats.mBeginIdleTime > deviceUsageTime) {
+ dstStats.mBeginIdleTime = deviceUsageTime;
+ }
+ }
+ }
+
+ /**
+ * App idle operates on a rolling window of time. When we roll over time, we end up with a
+ * period of time where in-memory stats are empty and we don't hit the disk for older stats
+ * for performance reasons. Suddenly all apps will become idle.
+ *
+ * Instead, at times we do a deep query to find all the apps that have run in the past few
+ * days and keep the cached data up to date.
+ *
+ * @param currentTimeMillis
+ */
+ void refreshAppIdleRollingWindow(final long currentTimeMillis, final long deviceUsageTime) {
+ // Start the rolling window for AppIdle requests.
+ final long startRangeMillis = currentTimeMillis -
+ mListener.getAppIdleRollingWindowDurationMillis();
+
+ List stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
+ startRangeMillis, currentTimeMillis, new StatCombiner() {
+ @Override
+ public void combine(IntervalStats stats, boolean mutable,
+ List accumulatedResult) {
+ IntervalStats accum;
+ if (accumulatedResult.isEmpty()) {
+ accum = new IntervalStats();
+ accum.beginTime = stats.beginTime;
+ accumulatedResult.add(accum);
+ } else {
+ accum = accumulatedResult.get(0);
+ }
+
+ mergePackageStats(accum, stats, deviceUsageTime);
+ }
+ });
+
+ if (stats == null || stats.isEmpty()) {
+ mAppIdleRollingWindow = new IntervalStats();
+ mergePackageStats(mAppIdleRollingWindow,
+ mCurrentStats[UsageStatsManager.INTERVAL_YEARLY], deviceUsageTime);
+ } else {
+ mAppIdleRollingWindow = stats.get(0);
+ }
}
//
@@ -552,6 +638,9 @@ void dump(IndentingPrintWriter pw, final long screenOnTime) {
pw.println(" stats");
printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true);
}
+
+ pw.println("AppIdleRollingWindow cache");
+ printIntervalStats(pw, mAppIdleRollingWindow, screenOnTime, true);
}
private String formatDateTime(long dateTime, boolean pretty) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 7eab808479b75..2886ce6f608b3 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -250,7 +250,8 @@ public void systemReady() {
final StorageManager storageManager = StorageManager.from(mContext);
final StorageVolume primary = storageManager.getPrimaryVolume();
massStorageSupported = primary != null && primary.allowMassStorage();
- mUseUsbNotification = !massStorageSupported;
+ mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_usbChargingMessage);
// make sure the ADB_ENABLED setting value matches the current state
try {
@@ -579,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);
@@ -894,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 36de974b2c044..438e7bb42bd29 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -230,8 +230,20 @@ public static class Details {
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
+ /**
+ * Remote device supports call transfers.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_TRANSFER = 0x04000000;
+
+ /**
+ * Call sends responses through connection.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x08000000;
+
//******************************************************************************************
- // Next CAPABILITY value: 0x04000000
+ // Next CAPABILITY value: 0x10000000
//******************************************************************************************
/**
@@ -400,6 +412,9 @@ public static String capabilitiesToString(int capabilities) {
if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) {
builder.append(" CAPABILITY_ADD_PARTICIPANT");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_TRANSFER)) {
+ builder.append(" CAPABILITY_SUPPORTS_TRANSFER");
+ }
builder.append("]");
return builder.toString();
}
@@ -816,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.
*
@@ -927,6 +952,15 @@ public void mergeConference() {
mInCallAdapter.mergeConference(mTelecomCallId);
}
+ /**
+ * Instructs this {@code Call} to connect the current active call and the call on hold.
+ * The current call will then disconnect. See {@link Details#CAPABILITY_SUPPORTS_TRANSFER}.
+ * @hide
+ */
+ public void transferCall() {
+ mInCallAdapter.transferCall(mTelecomCallId);
+ }
+
/**
* Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
*/
@@ -1148,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/Connection.java b/telecomm/java/android/telecom/Connection.java
index 01582a8475953..5e2ec3cfdb459 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -272,8 +272,21 @@ public abstract class Connection extends Conferenceable {
*/
public static final int CAPABILITY_SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE = 0x01000000;
+ /**
+ * Remote device supports call transfers.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_TRANSFER = 0x04000000;
+
+ /**
+ * Indicates that the connection itself wants to handle any sort of reply response, rather than
+ * relying on SMS.
+ * @hide
+ */
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x04000000
+ // Next CAPABILITY value: 0x00800000
//**********************************************************************************************
/**
@@ -458,6 +471,10 @@ public static String capabilitiesToString(int capabilities) {
if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+ builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+ }
+
builder.append("]");
return builder.toString();
}
@@ -1944,6 +1961,26 @@ public void onAnswer() {
*/
public void onReject() {}
+ /**
+ * Transfers the current call.
+ * @hide
+ */
+ public void onTransfer() { }
+
+ /**
+ * Notifies ths Connection of a request reject with a message.
+ *
+ * @hide
+ */
+ public void onReject(String replyMessage) {}
+
+ /**
+ * Notifies the Connection of a request to silence the ringer.
+ *
+ * @hide
+ */
+ public void onSilence() {}
+
/**
* Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
*/
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 9e4f9bbf5b811..f64fc99a8af42 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,7 +101,10 @@ public abstract class ConnectionService extends Service {
private static final int MSG_ANSWER_VIDEO = 17;
private static final int MSG_MERGE_CONFERENCE = 18;
private static final int MSG_SWAP_CONFERENCE = 19;
- private static final int MSG_SET_LOCAL_HOLD = 20;
+ private static final int MSG_REJECT_WITH_MESSAGE = 20;
+ private static final int MSG_SILENCE = 21;
+ private static final int MSG_SET_LOCAL_HOLD = 22;
+ private static final int MSG_EXPLICIT_TRANSFER = 23;
//Proprietary values starts after this.
private static final int MSG_ADD_PARTICIPANT_WITH_CONFERENCE = 30;
@@ -168,6 +171,19 @@ public void reject(String callId) {
mHandler.obtainMessage(MSG_REJECT, callId).sendToTarget();
}
+ @Override
+ public void rejectWithMessage(String callId, String message) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = message;
+ mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
+ }
+
+ @Override
+ public void silence(String callId) {
+ mHandler.obtainMessage(MSG_SILENCE, callId).sendToTarget();
+ }
+
@Override
public void disconnect(String callId) {
mHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
@@ -247,6 +263,11 @@ public void onPostDialContinue(String callId, boolean proceed) {
args.argi1 = proceed ? 1 : 0;
mHandler.obtainMessage(MSG_ON_POST_DIAL_CONTINUE, args).sendToTarget();
}
+
+ @Override
+ public void explicitTransfer(String callId) {
+ mHandler.obtainMessage(MSG_EXPLICIT_TRANSFER, callId).sendToTarget();
+ }
};
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -315,9 +336,21 @@ public void run() {
case MSG_REJECT:
reject((String) msg.obj);
break;
+ case MSG_REJECT_WITH_MESSAGE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ reject((String) args.arg1, (String) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_DISCONNECT:
disconnect((String) msg.obj);
break;
+ case MSG_SILENCE:
+ silence((String) msg.obj);
+ break;
case MSG_HOLD:
hold((String) msg.obj);
break;
@@ -394,6 +427,9 @@ public void run() {
}
break;
}
+ case MSG_EXPLICIT_TRANSFER:
+ transfer((String) msg.obj);
+ break;
default:
break;
}
@@ -748,6 +784,16 @@ private void reject(String callId) {
findConnectionForAction(callId, "reject").onReject();
}
+ private void reject(String callId, String rejectWithMessage) {
+ Log.d(this, "reject %s with message", callId);
+ findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
+ }
+
+ private void silence(String callId) {
+ Log.d(this, "silence %s", callId);
+ findConnectionForAction(callId, "silence").onSilence();
+ }
+
private void disconnect(String callId) {
Log.d(this, "disconnect %s", callId);
if (mConnectionById.containsKey(callId)) {
@@ -766,6 +812,11 @@ private void hold(String callId) {
}
}
+ private void transfer(String callId) {
+ Log.d(this, "transfer %s", callId);
+ findConnectionForAction(callId, "transfer").onTransfer();
+ }
+
private void unhold(String callId) {
Log.d(this, "unhold %s", callId);
if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 7d0f5a72d03c1..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.
*
@@ -240,6 +254,13 @@ public void mergeConference(String callId) {
}
}
+ public void transferCall(String callId) {
+ try {
+ mAdapter.transferCall(callId);
+ } catch (RemoteException ignored) {
+ }
+ }
+
/**
* Instructs Telecom to swap the child calls of the specified conference call.
*/
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index f890f4d15b36b..635a48be6fe6d 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -121,6 +121,14 @@ public final class PhoneAccount implements Parcelable {
*/
public static final int CAPABILITY_CALL_SUBJECT = 0x40;
+ /**
+ * Flag indicating that this {@code PhoneAccount} should only be used for emergency calls.
+ *
+ * See {@link #getCapabilities}
+ * @hide
+ */
+ public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
+
/**
* URI scheme for telephone number URIs.
*/
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 673adb2b0e0a7..ca9792b51233a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -116,6 +116,15 @@ public class TelecomManager {
public static final String ACTION_PHONE_ACCOUNT_REGISTERED =
"android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+ /**
+ * The {@link android.content.Intent} action used indicate that a phone account was
+ * just unregistered.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED =
+ "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
+
/**
* Activity action: Shows a dialog asking the user whether or not they want to replace the
* current default Dialer with the one specified in
@@ -367,6 +376,48 @@ public class TelecomManager {
public static final String EXTRA_TTY_PREFERRED_MODE =
"android.telecom.intent.extra.TTY_PREFERRED";
+ /**
+ * Broadcast intent action for letting custom component know to show the missed call
+ * notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_SHOW_MISSED_CALLS_NOTIFICATION =
+ "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
+
+ /**
+ * The number of calls associated with the notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NOTIFICATION_COUNT =
+ "android.telecom.extra.NOTIFICATION_COUNT";
+
+ /**
+ * The number associated with the missed calls. This number is only relevant
+ * when EXTRA_NOTIFICATION_COUNT is 1.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NOTIFICATION_PHONE_NUMBER =
+ "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
+
+ /**
+ * The intent to clear missed calls.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT =
+ "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
+
+ /**
+ * The intent to call back a missed call.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_CALL_BACK_INTENT =
+ "android.telecom.extra.CALL_BACK_INTENT";
+
/**
* The following 4 constants define how properties such as phone numbers and names are
* displayed to the user.
@@ -392,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/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 23d70d59230d7..398d2e1e7dc98 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -50,8 +50,12 @@ oneway interface IConnectionService {
void reject(String callId);
+ void rejectWithMessage(String callId, String message);
+
void disconnect(String callId);
+ void silence(String callId);
+
void hold(String callId);
void unhold(String callId);
@@ -75,4 +79,6 @@ oneway interface IConnectionService {
void setLocalCallHold(String callId, boolean lchState);
void addParticipantWithConference(String callId, String recipients);
+
+ void explicitTransfer(String callId);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index ee51efa691563..3104fb27a6ccb 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -62,4 +62,9 @@ oneway interface IInCallAdapter {
void turnOffProximitySensor(boolean screenOnImmediately);
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 29e54a32a4801..bd6662dd1bfd1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -421,12 +421,28 @@ public CarrierConfigManager() {
*/
public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+ /**
+ * Determine whether HD icon should displayed when audio codec is EVS.
+ * @hide
+ */
+ public static final String KEY_IMS_SUPPORT_EVS_HD_ICON_BOOL =
+ "carrier_ims_support_evs_hd_icon_bool";
+
/**
* Determine whether preferred network type can be shown.
* @hide
*/
public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+ /**
+ * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
+ * Some operators support Wi-Fi Calling only, not VoLTE.
+ * They don't need "Cellular preferred" option.
+ * In this case, set uneditalbe attribute for preferred preference.
+ * @hide
+ */
+ public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+
/**
* Specifies the amount of gap to be added in millis between postdial DTMF tones. When a
* non-zero value is specified, the UE shall wait for the specified amount of time before it
@@ -449,6 +465,13 @@ public CarrierConfigManager() {
*/
public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ /**
+ * Boolean indicating if intent for emergency call state changes should be broadcast
+ * @hide
+ */
+ public static final String KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL =
+ "broadcast_emergency_call_state_changes_bool";
+
// These variables are used by the MMS service and exposed through another API, {@link
// SmsManager}. The variable names and string values are copied from there.
public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -527,7 +550,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);
@@ -547,6 +570,7 @@ public CarrierConfigManager() {
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_ADDING_APNS_BOOL, true);
+ sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
@@ -559,7 +583,9 @@ public CarrierConfigManager() {
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
+ sDefaults.putBoolean(KEY_IMS_SUPPORT_EVS_HD_ICON_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
+ sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
// MMS defaults
@@ -612,12 +638,15 @@ public CarrierConfigManager() {
@Nullable
public PersistableBundle getConfigForSubId(int subId) {
try {
- return getICarrierConfigLoader().getConfigForSubId(subId);
+ ICarrierConfigLoader loader = getICarrierConfigLoader();
+ if (loader == null) {
+ Rlog.w(TAG, "Error getting config for subId " + subId
+ + " ICarrierConfigLoader is null");
+ return null;
+ }
+ return loader.getConfigForSubId(subId);
} catch (RemoteException ex) {
- Rlog.e(TAG, "Error getting config for subId " + Integer.toString(subId) + ": "
- + ex.toString());
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "Error getting config for subId " + Integer.toString(subId) + ": "
+ Rlog.e(TAG, "Error getting config for subId " + subId + ": "
+ ex.toString());
}
return null;
@@ -653,11 +682,15 @@ public PersistableBundle getConfig() {
*/
public void notifyConfigChangedForSubId(int subId) {
try {
- getICarrierConfigLoader().notifyConfigChangedForSubId(subId);
+ ICarrierConfigLoader loader = getICarrierConfigLoader();
+ if (loader == null) {
+ Rlog.w(TAG, "Error reloading config for subId=" + subId
+ + " ICarrierConfigLoader is null");
+ return;
+ }
+ loader.notifyConfigChangedForSubId(subId);
} catch (RemoteException ex) {
Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString());
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "Error reloading config for subId=" + subId + ": " + ex.toString());
}
}
@@ -673,11 +706,15 @@ public void notifyConfigChangedForSubId(int subId) {
@SystemApi
public void updateConfigForPhoneId(int phoneId, String simState) {
try {
- getICarrierConfigLoader().updateConfigForPhoneId(phoneId, simState);
+ ICarrierConfigLoader loader = getICarrierConfigLoader();
+ if (loader == null) {
+ Rlog.w(TAG, "Error updating config for phoneId=" + phoneId
+ + " ICarrierConfigLoader is null");
+ return;
+ }
+ loader.updateConfigForPhoneId(phoneId, simState);
} catch (RemoteException ex) {
Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString());
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "Error updating config for phoneId=" + phoneId + ": " + ex.toString());
}
}
@@ -693,6 +730,7 @@ public static PersistableBundle getDefaultConfig() {
}
/** @hide */
+ @Nullable
private ICarrierConfigLoader getICarrierConfigLoader() {
return ICarrierConfigLoader.Stub
.asInterface(ServiceManager.getService(Context.CARRIER_CONFIG_SERVICE));
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index cb68b6b0b30bc..1821f30ef206f 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -241,6 +241,8 @@ public class DisconnectCause {
/** EMERGENCY call failed with permanent fail cause */
public static final int EMERGENCY_PERM_FAILURE = 97;
+ public static final int NON_SELECTED_USER_CLEARING = 98;
+
/**
* Call was rejected due to number being blacklisted by user.
* {@@hide}
@@ -255,7 +257,7 @@ public class DisconnectCause {
// 4) Update toString() with the newly added disconnect type.
// 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause.
//
- // NextId: 98
+ // NextId: 99
//*********************************************************************************************
/** Smallest valid value for call disconnect codes. */
@@ -370,6 +372,8 @@ public static String toString(int cause) {
return "IMS_MERGED_SUCCESSFULLY";
case CDMA_ALREADY_ACTIVATED:
return "CDMA_ALREADY_ACTIVATED";
+ case NON_SELECTED_USER_CLEARING:
+ return "NON_SELECTED_USER_CLEARING";
case HO_NOT_FEASIBLE:
return "HO_NOT_FEASIBLE";
case NO_CIRCUIT_AVAIL:
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 5ee1fb2e6a5da..a70233f233782 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1935,11 +1935,13 @@ private static boolean isEmergencyNumberInternal(int subId, String number,
// It is not possible to append additional digits to an emergency number to dial
// the number in Brazil - it won't connect.
if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) {
- if (number.equals(emergencyNum)) {
+ if (number.equals(emergencyNum) &&
+ isEmergencyNumberForCurrentIso(number, defaultCountryIso, slotId)) {
return true;
}
} else {
- if (number.startsWith(emergencyNum)) {
+ if (number.startsWith(emergencyNum) &&
+ isEmergencyNumberForCurrentIso(number, defaultCountryIso, slotId)) {
return true;
}
}
@@ -1981,6 +1983,57 @@ private static boolean isEmergencyNumberInternal(int subId, String number,
return false;
}
+ /**
+ * When checking for ECC numbers the country (defaultCountryIso) passed in is not taken into
+ * consideration by the function isEmergencyNumberInternal(subId, number, defaultCountryIso,
+ * useExactMatchecclist) this causes the function to return TRUE even in the case when the
+ * number is not emergency for defaultCountryIso.
+ */
+ private static boolean isEmergencyNumberForCurrentIso(String number,
+ String country,
+ int slotId) {
+ Rlog.w(LOG_TAG, "isEmergencyNumberForCurrentIso: number =" + number + " iso=" + country);
+
+ String mccEccIso = "";
+ String mccEccIsoProp = (slotId == 0) ? "ril.mcc.ecc.iso" : ("ril.mcc.ecc.iso" + slotId);
+ mccEccIso = SystemProperties.get(mccEccIsoProp, "");
+
+ if (TextUtils.isEmpty(mccEccIso) || TextUtils.isEmpty(country) || slotId < 0 ||
+ isEmergencyIsoMatchCountryIso(mccEccIso, country)) {
+ Rlog.w(LOG_TAG, "MCC/ISO is empty or matches region for ECC#'s set via RIL db");
+ return true;
+ }
+
+ String mccEccList = "";
+ String mccEccListProp = (slotId == 0) ? "ril.mcc.ecclist" : ("ril.mcc.ecclist" + slotId);
+ mccEccList = SystemProperties.get(mccEccListProp, "");
+
+ if (!TextUtils.isEmpty(mccEccList)) {
+ for (String emergencyNum : mccEccList.split(",")) {
+ if (number.equals(emergencyNum)) {
+ Rlog.w(LOG_TAG, "Number " + number + " matches with " + mccEccListProp);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the two strings passed are equal ignoring the case
+ */
+ private static boolean isEmergencyIsoMatchCountryIso(String iso, String country) {
+ Rlog.w(LOG_TAG, "isEmergencyIsoMatchCountryIso: iso=" + iso + " country=" + country);
+
+ if(iso.equalsIgnoreCase(country)) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
/**
* Checks if a given number is an emergency number for the country that the user is in.
*
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1578b438eab9e..3b375e218cb8e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -343,6 +343,14 @@ public class SubscriptionManager {
*/
public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+
+ /**
+ * TelephonyProvider column name for enable channel60 alert in CB settings
+ *@hide
+ */
+ public static final String CB_CHANNEL_60_ALERT = "enable_channel_60_alerts";
+
/**
* TelephonyProvider column name for CMAS test alert in CB settings
*@hide
@@ -1389,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 0c52783f3bf0d..5ec6950d79930 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -608,6 +608,46 @@ public boolean isMultiSimEnabled() {
*/
public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
+ /**
+ * Broadcast intent action for letting custom component know to show voicemail notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION =
+ "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
+
+ /**
+ * The number of voice messages associated with the notification.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_NOTIFICATION_COUNT =
+ "android.telephony.extra.NOTIFICATION_COUNT";
+
+ /**
+ * The voicemail number.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_VOICEMAIL_NUMBER =
+ "android.telephony.extra.VOICEMAIL_NUMBER";
+
+ /**
+ * The intent to call voicemail.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_CALL_VOICEMAIL_INTENT =
+ "android.telephony.extra.CALL_VOICEMAIL_INTENT";
+
+ /**
+ * The intent to launch voicemail settings.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT =
+ "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
+
/**
* Response codes for sim activation. Activation completed successfully.
* @hide
@@ -739,7 +779,7 @@ public String getDeviceId(int slotId) {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
return null;
- return info.getDeviceIdForPhone(slotId);
+ return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -3028,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/ims/ImsCallForwardInfo.java b/telephony/java/com/android/ims/ImsCallForwardInfo.java
index 3f8fd19a16cec..97dcbd509d83e 100644
--- a/telephony/java/com/android/ims/ImsCallForwardInfo.java
+++ b/telephony/java/com/android/ims/ImsCallForwardInfo.java
@@ -31,6 +31,8 @@ public class ImsCallForwardInfo implements Parcelable {
public int mStatus;
// 0x91: International, 0x81: Unknown
public int mToA;
+ // Service class
+ public int mServiceClass;
// Number (it will not include the "sip" or "tel" URI scheme)
public String mNumber;
// No reply timer for CF
@@ -53,6 +55,7 @@ public void writeToParcel(Parcel out, int flags) {
out.writeInt(mCondition);
out.writeInt(mStatus);
out.writeInt(mToA);
+ out.writeInt(mServiceClass);
out.writeString(mNumber);
out.writeInt(mTimeSeconds);
}
@@ -62,6 +65,7 @@ public String toString() {
return super.toString() + ", Condition: " + mCondition
+ ", Status: " + ((mStatus == 0) ? "disabled" : "enabled")
+ ", ToA: " + mToA + ", Number=" + mNumber
+ + ", Service Class: " + mServiceClass
+ ", Time (seconds): " + mTimeSeconds;
}
@@ -69,6 +73,7 @@ private void readFromParcel(Parcel in) {
mCondition = in.readInt();
mStatus = in.readInt();
mToA = in.readInt();
+ mServiceClass = in.readInt();
mNumber = in.readString();
mTimeSeconds = in.readInt();
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 3ab415c12e445..85ec16298da4e 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -250,6 +250,14 @@ public class ImsReasonInfo implements Parcelable {
*/
public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+ /**
+ * Supplementary services (HOLD/RESUME) failure error codes.
+ * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+ */
+ public static final int CODE_SUPP_SVC_FAILED = 1201;
+ public static final int CODE_SUPP_SVC_CANCELLED = 1202;
+ public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203;
+
/**
* Network string error messages.
* mExtraMessage may have these values.
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4ab5ee3c4f8c7..278465353a1ff 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -111,4 +111,9 @@ interface IImsUt {
* Sets the listener.
*/
void setListener(in IImsUtListener listener);
+
+ /**
+ * Retrieves the configuration of the call forward for specified service class.
+ */
+ int queryCFForServiceClass(int condition, String number, int serviceClass);
}
diff --git a/telephony/java/com/android/internal/telephony/IExtTelephony.aidl b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl
index 063308d42de9c..7040f8079f682 100644
--- a/telephony/java/com/android/internal/telephony/IExtTelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/IExtTelephony.aidl
@@ -116,4 +116,56 @@ interface IExtTelephony {
* @return phone id
*/
int getPhoneIdForECall();
+
+ /**
+ * Check is FDN is enabled or not.
+ * @param - void
+ * @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/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index ed85392dd4d75..dc2b297f6dbe5 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -36,7 +36,7 @@ interface IPhoneSubInfo {
* Retrieves the unique device ID of a phone for the device, e.g., IMEI
* for GSM phones.
*/
- String getDeviceIdForPhone(int phoneId);
+ String getDeviceIdForPhone(int phoneId, String callingPackage);
/**
* Retrieves the IMEI.
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 13777348a0940..c7e13aa2ee37a 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -467,12 +467,17 @@ interface ISms {
*/
String getImsSmsFormatForSubscriber(int subId);
- /*
+ /**
* Get SMS prompt property, enabled or not
* @return true if enabled, false otherwise
*/
boolean isSMSPromptEnabled();
+ /**
+ * Set SMS prompt property, enabled or not
+ */
+ void setSMSPromptEnabled(boolean bool);
+
/**
* Send a system stored text message.
*
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/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 5fd7d5e6bc041..ca3c8a8c9fc48 100755
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -35,17 +35,17 @@ public enum State {
IDLE, RINGING, OFFHOOK;
};
- /**
- * The state of a data connection.
- *
- * - CONNECTED = IP traffic should be available
- * - CONNECTING = Currently setting up data connection
- * - DISCONNECTED = IP not available
- * - SUSPENDED = connection is created but IP traffic is
- * temperately not available. i.e. voice call is in place
- * in 2G network
- *
- */
+ /**
+ * The state of a data connection.
+ *
+ * - CONNECTED = IP traffic should be available
+ * - CONNECTING = Currently setting up data connection
+ * - DISCONNECTED = IP not available
+ * - SUSPENDED = connection is created but IP traffic is
+ * temperately not available. i.e. voice call is in place
+ * in 2G network
+ *
+ */
public enum DataState {
CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED;
};
@@ -86,6 +86,7 @@ public enum DataState {
public static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
public static final String DATA_NETWORK_ROAMING_KEY = "networkRoaming";
public static final String PHONE_IN_ECM_STATE = "phoneinECMState";
+ public static final String PHONE_IN_EMERGENCY_CALL = "phoneInEmergencyCall";
public static final String REASON_LINK_PROPERTIES_CHANGED = "linkPropertiesChanged";
@@ -199,4 +200,7 @@ public enum CardUnavailableReason {
public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
+
+ /** Copied from ContactsCommon. See comments in ContactsCommon app for more detail. */
+ public static final String EXTRA_CALL_ORIGIN = "com.android.phone.CALL_ORIGIN";
}
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/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index f563839e2c937..77b8a6785c84d 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -75,6 +75,7 @@ public class TelephonyIntents {
*/
public static final String ACTION_RADIO_TECHNOLOGY_CHANGED
= "android.intent.action.RADIO_TECHNOLOGY";
+
/**
* Broadcast Action: The emergency callback mode is changed.
*
@@ -94,6 +95,28 @@ public class TelephonyIntents {
*/
public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED
= "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
+
+ /**
+ * Broadcast Action: The emergency call state is changed.
+ *
+ * - phoneInEmergencyCall - A boolean value, true if phone in emergency call,
+ * false otherwise
+ *
+ *
+ * You can not receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
+ * android.content.IntentFilter) Context.registerReceiver()}.
+ *
+ *
+ * Requires no permission.
+ *
+ *
This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED
+ = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
+
/**
* Broadcast Action: The phone's signal strength has changed. The intent will have the
* following extra values:
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 7aacb2345768c..bd0a89a94bd7b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -891,6 +891,7 @@ public VerifierDeviceIdentity getVerifierDeviceIdentity() {
public boolean isUpgrade() {
throw new UnsupportedOperationException();
}
+
/**
* @hide
*/
@@ -899,6 +900,15 @@ public void setComponentProtectedSetting(ComponentName componentName, boolean ne
throw new UnsupportedOperationException();
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isComponentProtected(String callingPackage, int callingUid,
+ ComponentName componentName) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @hide
*/
diff --git a/tests/UiBench/.gitignore b/tests/UiBench/.gitignore
new file mode 100644
index 0000000000000..c39eac2a6309b
--- /dev/null
+++ b/tests/UiBench/.gitignore
@@ -0,0 +1,5 @@
+.gradle
+.idea
+*.iml
+build
+local.properties
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
new file mode 100644
index 0000000000000..0e678cde9c70e
--- /dev/null
+++ b/tests/UiBench/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# omit gradle 'build' dir
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+# use appcompat/support lib from the tree, so improvements/
+# regressions are reflected in test data
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/cardview/res \
+ frameworks/support/v7/recyclerview/res
+
+LOCAL_AAPT_FLAGS := \
+ --auto-add-overlay \
+ --extra-packages android.support.v7.appcompat \
+ --extra-packages android.support.v7.cardview \
+ --extra-packages android.support.v7.recyclerview
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-cardview \
+ android-support-v7-recyclerview
+
+LOCAL_PACKAGE_NAME := UiBench
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
new file mode 100644
index 0000000000000..7b4f01cad8495
--- /dev/null
+++ b/tests/UiBench/AndroidManifest.xml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
new file mode 100644
index 0000000000000..0756a8aac8789
--- /dev/null
+++ b/tests/UiBench/build.gradle
@@ -0,0 +1,39 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.0'
+
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "22.0.0"
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ res.srcDirs = ['res']
+ }
+ }
+}
+
+dependencies {
+ // Dependencies enumerated specifically for platform-independent / reproducible builds.
+ compile 'com.android.support:support-v4:23.0.1'
+ compile 'com.android.support:appcompat-v7:23.0.1'
+ compile 'com.android.support:cardview-v7:23.0.1'
+ compile 'com.android.support:recyclerview-v7:23.0.1'
+}
diff --git a/tests/UiBench/gradle/wrapper/gradle-wrapper.jar b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000..8c0fb64a8698b
Binary files /dev/null and b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/tests/UiBench/gradle/wrapper/gradle-wrapper.properties b/tests/UiBench/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000..12582f8e993ed
--- /dev/null
+++ b/tests/UiBench/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Aug 26 10:51:13 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
diff --git a/tests/UiBench/res/drawable-nodpi/ball.jpg b/tests/UiBench/res/drawable-nodpi/ball.jpg
new file mode 100644
index 0000000000000..2960b7309f6e1
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/ball.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/block.jpg b/tests/UiBench/res/drawable-nodpi/block.jpg
new file mode 100644
index 0000000000000..04c22a0cf5b47
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/block.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/ducky.jpg b/tests/UiBench/res/drawable-nodpi/ducky.jpg
new file mode 100644
index 0000000000000..830bbe347e47f
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/ducky.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/frantic.jpg b/tests/UiBench/res/drawable-nodpi/frantic.jpg
new file mode 100644
index 0000000000000..4c623336e15b4
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/frantic.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/jellies.jpg b/tests/UiBench/res/drawable-nodpi/jellies.jpg
new file mode 100644
index 0000000000000..ee2b5c68c43be
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/jellies.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/large_photo.jpg b/tests/UiBench/res/drawable-nodpi/large_photo.jpg
new file mode 100644
index 0000000000000..e23dbb093f39d
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/large_photo.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/mug.jpg b/tests/UiBench/res/drawable-nodpi/mug.jpg
new file mode 100644
index 0000000000000..e149e198a9cd7
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/mug.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/pencil.jpg b/tests/UiBench/res/drawable-nodpi/pencil.jpg
new file mode 100644
index 0000000000000..e348311bf4d08
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/pencil.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/scissors.jpg b/tests/UiBench/res/drawable-nodpi/scissors.jpg
new file mode 100644
index 0000000000000..caf0ce8e2f4b0
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/scissors.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/woot.jpg b/tests/UiBench/res/drawable-nodpi/woot.jpg
new file mode 100644
index 0000000000000..ccaef674b1a5d
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/woot.jpg differ
diff --git a/tests/UiBench/res/layout/activity_bitmap_upload.xml b/tests/UiBench/res/layout/activity_bitmap_upload.xml
new file mode 100644
index 0000000000000..70faa07a6d753
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_bitmap_upload.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_invalidate.xml b/tests/UiBench/res/layout/activity_invalidate.xml
new file mode 100644
index 0000000000000..34bcca95f79f4
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_invalidate.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
new file mode 100644
index 0000000000000..d4c661027a353
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_transition_details.xml b/tests/UiBench/res/layout/activity_transition_details.xml
new file mode 100644
index 0000000000000..1022d2fc2a40d
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition_details.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/card_row.xml b/tests/UiBench/res/layout/card_row.xml
new file mode 100644
index 0000000000000..215f9df9b7fdd
--- /dev/null
+++ b/tests/UiBench/res/layout/card_row.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/invalidate_row.xml b/tests/UiBench/res/layout/invalidate_row.xml
new file mode 100644
index 0000000000000..9feefde0bbfa5
--- /dev/null
+++ b/tests/UiBench/res/layout/invalidate_row.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
new file mode 100644
index 0000000000000..54c5b5845ae20
--- /dev/null
+++ b/tests/UiBench/res/layout/recycler_view.xml
@@ -0,0 +1,21 @@
+
+
+
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
new file mode 100644
index 0000000000000..1106a13bfc2ad
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.app.ActivityOptions;
+import android.app.SharedElementCallback;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.Map;
+
+public class ActivityTransition extends AppCompatActivity {
+ private static final String KEY_ID = "ViewTransitionValues:id";
+
+ private ImageView mHero;
+
+ public static final int[] DRAWABLES = {
+ R.drawable.ball,
+ R.drawable.block,
+ R.drawable.ducky,
+ R.drawable.jellies,
+ R.drawable.mug,
+ R.drawable.pencil,
+ R.drawable.scissors,
+ R.drawable.woot,
+ };
+
+ public static final int[] IDS = {
+ R.id.ball,
+ R.id.block,
+ R.id.ducky,
+ R.id.jellies,
+ R.id.mug,
+ R.id.pencil,
+ R.id.scissors,
+ R.id.woot,
+ };
+
+ public static final String[] NAMES = {
+ "ball",
+ "block",
+ "ducky",
+ "jellies",
+ "mug",
+ "pencil",
+ "scissors",
+ "woot",
+ };
+
+ public static int getIdForKey(String id) {
+ return IDS[getIndexForKey(id)];
+ }
+
+ public static int getDrawableIdForKey(String id) {
+ return DRAWABLES[getIndexForKey(id)];
+ }
+
+ public static int getIndexForKey(String id) {
+ for (int i = 0; i < NAMES.length; i++) {
+ String name = NAMES[i];
+ if (name.equals(id)) {
+ return i;
+ }
+ }
+ return 2;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+ setContentView(R.layout.activity_transition);
+ setupHero();
+ }
+
+ private void setupHero() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ mHero = null;
+ if (name != null) {
+ mHero = (ImageView) findViewById(getIdForKey(name));
+ setEnterSharedElementCallback(new SharedElementCallback() {
+ @Override
+ public void onMapSharedElements(List names,
+ Map sharedElements) {
+ sharedElements.put("hero", mHero);
+ }
+ });
+ }
+ }
+
+ public void clicked(View v) {
+ mHero = (ImageView) v;
+ Intent intent = new Intent(this, ActivityTransitionDetails.class);
+ intent.putExtra(KEY_ID, v.getTransitionName());
+ ActivityOptions activityOptions
+ = ActivityOptions.makeSceneTransitionAnimation(this, mHero, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
new file mode 100644
index 0000000000000..a654c61071340
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.test.uibench.ActivityTransition;
+import com.android.test.uibench.R;
+
+
+public class ActivityTransitionDetails extends AppCompatActivity {
+ private static final String KEY_ID = "ViewTransitionValues:id";
+ private int mImageResourceId = R.drawable.ducky;
+ private String mName = "ducky";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.DKGRAY));
+ setContentView(R.layout.activity_transition_details);
+ ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
+ titleImage.setImageDrawable(getHeroDrawable());
+ }
+
+ private Drawable getHeroDrawable() {
+ String name = getIntent().getStringExtra(KEY_ID);
+ if (name != null) {
+ mName = name;
+ mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
+ }
+
+ return getResources().getDrawable(mImageResourceId);
+ }
+
+ public void clicked(View v) {
+ Intent intent = new Intent(this, ActivityTransition.class);
+ intent.putExtra(KEY_ID, mName);
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
+ this, v, "hero");
+ startActivity(intent, activityOptions.toBundle());
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java b/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java
new file mode 100644
index 0000000000000..e2bf8976a3157
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+public class BitmapUploadActivity extends AppCompatActivity {
+ public static class UploadView extends View {
+ private int mColorValue;
+ private Bitmap mBitmap;
+ private final DisplayMetrics mMetrics = new DisplayMetrics();
+ private final Rect mRect = new Rect();
+
+ public UploadView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @SuppressWarnings("unused")
+ public void setColorValue(int colorValue) {
+ if (colorValue == mColorValue) return;
+
+ mColorValue = colorValue;
+
+ // modify the bitmap's color to ensure it's uploaded to the GPU
+ mBitmap.eraseColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+ invalidate();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ getDisplay().getMetrics(mMetrics);
+ int minDisplayDimen = Math.min(mMetrics.widthPixels, mMetrics.heightPixels);
+ int bitmapSize = Math.min((int) (minDisplayDimen * 0.75), 720);
+ if (mBitmap == null
+ || mBitmap.getWidth() != bitmapSize
+ || mBitmap.getHeight() != bitmapSize) {
+ mBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mBitmap != null) {
+ mRect.set(0, 0, getWidth(), getHeight());
+ canvas.drawBitmap(mBitmap, null, mRect, null);
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_bitmap_upload);
+
+ // animate color to force bitmap uploads
+ UploadView uploadView = (UploadView) findViewById(R.id.upload_view);
+ ObjectAnimator colorValueAnimator = ObjectAnimator.ofInt(uploadView, "colorValue", 0, 255);
+ colorValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ colorValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ colorValueAnimator.start();
+
+ // animate scene root to guarantee there's a minimum amount of GPU rendering work
+ View uploadRoot = findViewById(R.id.upload_root);
+ ObjectAnimator yAnimator = ObjectAnimator.ofFloat(uploadRoot, "translationY", 0, 100);
+ yAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ yAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ yAnimator.start();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
new file mode 100644
index 0000000000000..fe712d5230bb6
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class DialogListActivity extends AppCompatActivity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ListView listView = new ListView(this);
+ listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+ TextUtils.buildSimpleStringList()));
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Dialog");
+ builder.setView(listView);
+ builder.create().show();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java b/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java
new file mode 100644
index 0000000000000..08ab5105a5e8d
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.support.v7.app.AppCompatActivity;
+import android.view.KeyEvent;
+import android.widget.EditText;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * Note: currently incomplete, complexity of input continuously grows, instead of looping
+ * over a stable amount of work.
+ *
+ * Simulates typing continuously into an EditText.
+ */
+public class EditTextTypeActivity extends AppCompatActivity {
+ Thread mThread;
+
+ private static String sSeedText = "";
+ static {
+ final int count = 100;
+ final String string = "hello ";
+
+ StringBuilder builder = new StringBuilder(count * string.length());
+ for (int i = 0; i < count; i++) {
+ builder.append(string);
+ }
+ sSeedText = builder.toString();
+ }
+
+ final Object mLock = new Object();
+ boolean mShouldStop = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ EditText editText = new EditText(this);
+ editText.setText(sSeedText);
+ setContentView(editText);
+
+ final Instrumentation instrumentation = new Instrumentation();
+ final Semaphore sem = new Semaphore(0);
+ MessageQueue.IdleHandler handler = new MessageQueue.IdleHandler() {
+ @Override
+ public boolean queueIdle() {
+ // TODO: consider other signaling approaches
+ sem.release();
+ return true;
+ }
+ };
+ Looper.myQueue().addIdleHandler(handler);
+ synchronized (mLock) {
+ mShouldStop = false;
+ }
+ mThread = new Thread(new Runnable() {
+ int codes[] = { KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_L,
+ KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_SPACE };
+ int i = 0;
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ sem.acquire();
+ } catch (InterruptedException e) {
+ // TODO, maybe
+ }
+ int code = codes[i % codes.length];
+ if (i % 100 == 99) code = KeyEvent.KEYCODE_ENTER;
+
+ synchronized (mLock) {
+ if (mShouldStop) break;
+ }
+
+ // TODO: bit of a race here, since the event can arrive after pause/stop.
+ // (Can't synchronize on key send, since it's synchronous.)
+ instrumentation.sendKeyDownUpSync(code);
+ i++;
+ }
+ }
+ });
+ mThread.start();
+ }
+
+ @Override
+ protected void onPause() {
+ synchronized (mLock) {
+ mShouldStop = true;
+ }
+ super.onPause();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java b/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java
new file mode 100644
index 0000000000000..f1ecc5624d577
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+/**
+ * Draws hundreds of levels of overdraw over the content area.
+ *
+ * This should all be optimized out by the renderer.
+ */
+public class FullscreenOverdrawActivity extends AppCompatActivity {
+ private class OverdrawView extends View {
+ Paint paint = new Paint();
+ int mColorValue = 0;
+
+ public OverdrawView(Context context) {
+ super(context);
+ }
+
+ @SuppressWarnings("unused")
+ public void setColorValue(int colorValue) {
+ mColorValue = colorValue;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ paint.setColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+ for (int i = 0; i < 400; i++) {
+ canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
+ }
+ }
+ }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ OverdrawView overdrawView = new OverdrawView(this);
+ setContentView(overdrawView);
+
+ ObjectAnimator objectAnimator = ObjectAnimator.ofInt(overdrawView, "colorValue", 0, 255);
+ objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ objectAnimator.start();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
new file mode 100644
index 0000000000000..a12742d83fe7d
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.test.uibench.opengl.ImageFlipRenderThread;
+
+public class GlTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
+ private ImageFlipRenderThread mRenderThread;
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+ setContentView(mTextureView, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+ Gravity.CENTER));
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ mRenderThread = new ImageFlipRenderThread(getResources(), surface);
+ mRenderThread.start();
+
+ mTextureView.setCameraDistance(5000);
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(4000);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mTextureView.invalidate();
+ }
+ });
+ animator.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ mRenderThread.finish();
+ try {
+ mRenderThread.join();
+ } catch (InterruptedException e) {
+ Log.e(ImageFlipRenderThread.LOG_TAG, "Could not wait for render thread");
+ }
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
+
+}
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
new file mode 100644
index 0000000000000..603244eb2a435
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class InflatingListActivity extends CompatListActivity {
+ @Override
+ protected ListAdapter createListAdapter() {
+ return new ArrayAdapter(this,
+ android.R.layout.simple_list_item_1, TextUtils.buildSimpleStringList()) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // pathological getView behavior: drop convertView on the floor to force inflation
+ return super.getView(position, null, parent);
+ }
+ };
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java b/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java
new file mode 100644
index 0000000000000..93d67a60515f6
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Tests invalidation performance by invalidating a large number of easily rendered views,
+ */
+public class InvalidateActivity extends AppCompatActivity {
+ public static class ColorView extends View {
+ @ColorInt
+ public int mColor;
+
+ public ColorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setColor(@ColorInt int color) {
+ mColor = color;
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(mColor);
+ }
+ }
+
+ ColorView[][] mColorViews;
+
+ @SuppressWarnings("unused")
+ public void setColorValue(int colorValue) {
+ @ColorInt int a = Color.rgb(colorValue, 255 - colorValue, 255);
+ @ColorInt int b = Color.rgb(255, colorValue, 255 - colorValue);
+ for (int y = 0; y < mColorViews.length; y++) {
+ for (int x = 0; x < mColorViews[y].length; x++) {
+ mColorViews[y][x].setColor((x + y) % 2 == 0 ? a : b);
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_invalidate);
+
+ ViewGroup root = (ViewGroup) findViewById(R.id.invalidate_root);
+ for (int y = 0; y < root.getChildCount(); y++) {
+ ViewGroup row = (ViewGroup) root.getChildAt(y);
+ if (mColorViews == null) {
+ mColorViews = new ColorView[root.getChildCount()][row.getChildCount()];
+ }
+
+ for (int x = 0; x < row.getChildCount(); x++) {
+ mColorViews[y][x] = (ColorView) row.getChildAt(x);
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofInt(this, "colorValue", 0, 255);
+ animator.setRepeatMode(ValueAnimator.REVERSE);
+ animator.setRepeatCount(ValueAnimator.INFINITE);
+ animator.start();
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/MainActivity.java b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
new file mode 100644
index 0000000000000..2111274a93c0b
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.test.uibench;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity {
+ private static final String EXTRA_PATH = "activity_path";
+ private static final String CATEGORY_HWUI_TEST = "com.android.test.uibench.TEST";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ String path = intent.getStringExtra(EXTRA_PATH);
+
+ if (path == null) {
+ path = "";
+ } else {
+ // not root level, display where we are in the hierarchy
+ setTitle(path);
+ }
+
+ FragmentManager fm = getSupportFragmentManager();
+ if (fm.findFragmentById(android.R.id.content) == null) {
+ ListFragment listFragment = new ListFragment() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ Map map = (Map)l.getItemAtPosition(position);
+
+ Intent intent = (Intent) map.get("intent");
+ startActivity(intent);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getListView().setTextFilterEnabled(true);
+ }
+ };
+ listFragment.setListAdapter(new SimpleAdapter(this, getData(path),
+ android.R.layout.simple_list_item_1, new String[] { "title" },
+ new int[] { android.R.id.text1 }));
+ fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+ }
+ }
+
+ protected List