summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java63
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java14
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java6
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityStack.java53
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java42
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java16
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java10
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java24
-rw-r--r--services/core/java/com/android/server/notification/ValidateNotificationPeople.java80
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/task/TaskManagerService.java171
-rw-r--r--services/core/java/com/android/server/task/TaskServiceContext.java2
-rw-r--r--services/core/java/com/android/server/task/TaskStore.java9
-rw-r--r--services/core/java/com/android/server/task/controllers/ConnectivityController.java10
-rw-r--r--services/core/java/com/android/server/task/controllers/TaskStatus.java39
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java9
-rw-r--r--services/core/java/com/android/server/trust/TrustArchive.java14
-rw-r--r--services/core/java/com/android/server/tv/TvInputHal.java128
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java308
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java63
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java48
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java42
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java2
-rw-r--r--services/core/jni/Android.mk1
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp388
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java2
30 files changed, 1364 insertions, 206 deletions
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7ecf248..5527528 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -343,12 +343,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final int EVENT_INET_CONDITION_HOLD_END = 5;
/**
- * used internally to set enable/disable cellular data
- * arg1 = ENBALED or DISABLED
- */
- private static final int EVENT_SET_MOBILE_DATA = 7;
-
- /**
* used internally to clear a wakelock when transitioning
* from one net to another
*/
@@ -1822,20 +1816,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return true;
}
- /**
- * @see ConnectivityManager#getMobileDataEnabled()
- */
- public boolean getMobileDataEnabled() {
- // TODO: This detail should probably be in DataConnectionTracker's
- // which is where we store the value and maybe make this
- // asynchronous.
- enforceAccessPermission();
- boolean retVal = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.MOBILE_DATA, 1) == 1;
- if (VDBG) log("getMobileDataEnabled returning " + retVal);
- return retVal;
- }
-
public void setDataDependency(int networkType, boolean met) {
enforceConnectivityInternalPermission();
@@ -1908,22 +1888,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
};
- /**
- * @see ConnectivityManager#setMobileDataEnabled(boolean)
- */
- public void setMobileDataEnabled(boolean enabled) {
- enforceChangePermission();
- if (DBG) log("setMobileDataEnabled(" + enabled + ")");
-
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
- (enabled ? ENABLED : DISABLED), 0));
- }
-
- private void handleSetMobileData(boolean enabled) {
- // TODO - handle this - probably generalize passing in a transport type and send to the
- // factories?
- }
-
@Override
public void setPolicyDataEnable(int networkType, boolean enabled) {
// only someone like NPMS should only be calling us
@@ -3315,11 +3279,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
handleInetConditionHoldEnd(netType, sequence);
break;
}
- case EVENT_SET_MOBILE_DATA: {
- boolean enabled = (msg.arg1 == ENABLED);
- handleSetMobileData(enabled);
- break;
- }
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
handleDeprecatedGlobalHttpProxy();
break;
@@ -5647,16 +5606,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
boolean isNewDefault = false;
if (DBG) log("handleConnectionValidated for "+newNetwork.name());
// check if any NetworkRequest wants this NetworkAgent
- // first check if it satisfies the NetworkCapabilities
ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ if (newNetwork == currentNetwork) {
+ if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" +
+ " request " + nri.request.requestId + ". No change.");
+ keep = true;
+ continue;
+ }
+
+ // check if it satisfies the NetworkCapabilities
if (VDBG) log(" checking if request is satisfied: " + nri.request);
if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
newNetwork.networkCapabilities)) {
// next check if it's better than any current network we're using for
// this request
- NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
if (VDBG) {
log("currentScore = " +
(currentNetwork != null ? currentNetwork.currentScore : 0) +
@@ -5785,12 +5751,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
if (state == NetworkInfo.State.CONNECTED) {
- // TODO - check if we want it (optimization)
try {
+ // This is likely caused by the fact that this network already
+ // exists. An example is when a network goes from CONNECTED to
+ // CONNECTING and back (like wifi on DHCP renew).
+ // TODO: keep track of which networks we've created, or ask netd
+ // to tell us whether we've already created this network or not.
mNetd.createNetwork(networkAgent.network.netId);
} catch (Exception e) {
- loge("Error creating Network " + networkAgent.network.netId);
+ loge("Error creating network " + networkAgent.network.netId + ": "
+ + e.getMessage());
+ return;
}
+
updateLinkProperties(networkAgent, null);
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 88bebcb..fc808ec 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7085,6 +7085,10 @@ public final class ActivityManagerService extends ActivityManagerNative
* Creates a new RecentTaskInfo from a TaskRecord.
*/
private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
+ // Update the task description to reflect any changes in the task stack
+ tr.updateTaskDescription();
+
+ // Compose the recent task info
ActivityManager.RecentTaskInfo rti
= new ActivityManager.RecentTaskInfo();
rti.id = tr.mActivities.isEmpty() ? -1 : tr.taskId;
@@ -9574,11 +9578,13 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mRecentTasks = mTaskPersister.restoreTasksLocked();
- if (!mRecentTasks.isEmpty()) {
- mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);
+ if (mRecentTasks == null) {
+ mRecentTasks = mTaskPersister.restoreTasksLocked();
+ if (!mRecentTasks.isEmpty()) {
+ mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks);
+ }
+ mTaskPersister.startPersisting();
}
- mTaskPersister.startPersisting();
// Check to see if there are any update receivers to run.
if (!mDidUpdate) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index b948c41..b429b93 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1154,13 +1154,15 @@ final class ActivityRecord {
}
if (intent == null) {
- Slog.e(TAG, "restoreActivity error intent=" + intent);
- return null;
+ throw new XmlPullParserException("restoreActivity error intent=" + intent);
}
final ActivityManagerService service = stackSupervisor.mService;
final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
null, userId);
+ if (aInfo == null) {
+ throw new XmlPullParserException("restoreActivity resolver error.");
+ }
final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
null, null, 0, componentSpecified, stackSupervisor, null, null);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d0ba118..8f60b03 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -37,6 +37,7 @@ import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
@@ -346,6 +347,10 @@ final class ActivityStack {
mWindowManager = mService.mWindowManager;
mStackId = activityContainer.mStackId;
mCurrentUser = mService.mCurrentUserId;
+ // Get the activity screenshot thumbnail dimensions
+ Resources res = mService.mContext.getResources();
+ mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+ mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
}
/**
@@ -729,42 +734,54 @@ final class ActivityStack {
}
}
+ /**
+ * This resets the saved state from the last screenshot, forcing a new screenshot to be taken
+ * again when requested.
+ */
+ private void invalidateLastScreenshot() {
+ mLastScreenshotActivity = null;
+ if (mLastScreenshotBitmap != null) {
+ mLastScreenshotBitmap.recycle();
+ }
+ mLastScreenshotBitmap = null;
+ }
+
public final Bitmap screenshotActivities(ActivityRecord who) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG, "screenshotActivities: " + who);
if (who.noDisplay) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tNo display");
return null;
}
TaskRecord tr = who.task;
- if (mService.getMostRecentTask() != tr && tr.intent != null &&
- (tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0) {
- // If this task is being excluded from recents, we don't want to take
- // the expense of capturing a thumbnail, since we will never show it.
+ if (mService.getMostRecentTask() != tr || isHomeStack()) {
+ // This is an optimization -- since we never show Home or Recents within Recents itself,
+ // we can just go ahead and skip taking the screenshot if this is the home stack. In
+ // the case where the most recent task is not the task that was supplied, then the stack
+ // has changed, so invalidate the last screenshot().
+ invalidateLastScreenshot();
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tIs Home stack? " + isHomeStack());
return null;
}
- Resources res = mService.mContext.getResources();
int w = mThumbnailWidth;
int h = mThumbnailHeight;
- if (w < 0) {
- mThumbnailWidth = w =
- res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
- mThumbnailHeight = h =
- res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
- }
-
if (w > 0) {
if (who != mLastScreenshotActivity || mLastScreenshotBitmap == null
|| mLastScreenshotActivity.state == ActivityState.RESUMED
|| mLastScreenshotBitmap.getWidth() != w
|| mLastScreenshotBitmap.getHeight() != h) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tUpdating screenshot");
mLastScreenshotActivity = who;
mLastScreenshotBitmap = mWindowManager.screenshotApplications(
who.appToken, Display.DEFAULT_DISPLAY, w, h, SCREENSHOT_FORCE_565);
}
if (mLastScreenshotBitmap != null) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG, "\tReusing last screenshot");
return mLastScreenshotBitmap.copy(mLastScreenshotBitmap.getConfig(), true);
}
}
+ Slog.e(TAG, "Invalid thumbnail dimensions: " + w + "x" + h);
return null;
}
@@ -1042,6 +1059,12 @@ final class ActivityStack {
} else {
next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
}
+
+ // If we are resuming the activity that we had last screenshotted, then we know it will be
+ // updated, so invalidate the last screenshot to ensure we take a fresh one when requested
+ if (next == mLastScreenshotActivity) {
+ invalidateLastScreenshot();
+ }
}
private void setVisibile(ActivityRecord r, boolean visible) {
@@ -1837,7 +1860,7 @@ final class ActivityStack {
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
- r.userId, r.info.configChanges);
+ r.userId, r.info.configChanges, task.voiceSession != null);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1898,7 +1921,7 @@ final class ActivityStack {
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
- r.info.configChanges);
+ r.info.configChanges, task.voiceSession != null);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1943,7 +1966,7 @@ final class ActivityStack {
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
- r.info.configChanges);
+ r.info.configChanges, task.voiceSession != null);
ActivityOptions.abort(options);
options = null;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c1a4643..6d20a32 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -109,6 +109,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_STATES = DEBUG || false;
static final boolean DEBUG_IDLE = DEBUG || false;
+ static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
public static final int HOME_STACK_ID = 0;
@@ -1212,8 +1213,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
- resultRecord.removeResultsLocked(
- sourceRecord, resultWho, requestCode);
+ resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
if (sourceRecord.launchedFromUid == callingUid) {
// The new activity is being launched from the same uid as the previous
@@ -1385,7 +1385,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
return err;
}
- ActivityStack adjustStackFocus(ActivityRecord r) {
+ ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
final TaskRecord task = r.task;
if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
if (task != null) {
@@ -1410,7 +1410,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return container.mStack;
}
- if (mFocusedStack != mHomeStack) {
+ if (mFocusedStack != mHomeStack && (!newTask ||
+ mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
"adjustStackFocus: Have a focused stack=" + mFocusedStack);
return mFocusedStack;
@@ -1463,7 +1464,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
- mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+ mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
// If the caller has asked not to resume at this point, we make note
@@ -1473,7 +1474,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
r.delayedResume = true;
}
- ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+ ActivityRecord notTop =
+ (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
// If the onlyIfNeeded flag is set, then we can do this if the activity
// being launched is the same as the one making the call... or, as
@@ -1496,9 +1498,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ launchFlags = intent.getFlags();
break;
case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ launchFlags = intent.getFlags();
break;
}
final boolean newDocument = intent.isDocument();
@@ -1804,7 +1808,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- targetStack = adjustStackFocus(r);
+ newTask = true;
+ targetStack = adjustStackFocus(r, newTask);
targetStack.moveToFront();
if (reuseTask == null) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
@@ -1821,7 +1826,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
} else {
r.setTask(reuseTask, reuseTask, true);
}
- newTask = true;
if (!movedHome) {
if ((launchFlags &
(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
@@ -1889,7 +1893,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// This not being started from an existing activity, and not part
// of a new task... just put it in the top task, though these days
// this case should never happen.
- targetStack = adjustStackFocus(r);
+ targetStack = adjustStackFocus(r, newTask);
targetStack.moveToFront();
ActivityRecord prev = targetStack.topActivity();
r.setTask(prev != null ? prev.task
@@ -2286,7 +2290,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
mWindowManager.addAppToken(0, r.appToken, taskId, stackId,
r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
- r.userId, r.info.configChanges);
+ r.userId, r.info.configChanges, task.voiceSession != null);
}
mWindowManager.addTask(taskId, stackId, false);
}
@@ -2316,7 +2320,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!r.isApplicationActivity() && !stack.isHomeStack()) {
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
+ if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
+ continue;
+ }
+ if (!stack.mActivityContainer.isEligibleForNewTasks()) {
+ if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
+ stack);
continue;
}
final ActivityRecord ar = stack.findTaskLocked(r);
@@ -3247,6 +3256,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
void setDrawn() {
}
+ // You can always start a new task on a regular ActivityStack.
+ boolean isEligibleForNewTasks() {
+ return true;
+ }
+
@Override
public String toString() {
return mIdString + (mActivityDisplay == null ? "N" : "A");
@@ -3327,6 +3341,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
}
+ // Never start a new task on an ActivityView if it isn't explicitly specified.
+ @Override
+ boolean isEligibleForNewTasks() {
+ return false;
+ }
+
private void setSurfaceIfReady() {
if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index ba3f2fe..3bfaca9 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -155,6 +155,7 @@ public class TaskPersister {
File taskFile = recentFiles[taskNdx];
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
BufferedReader reader = null;
+ boolean deleteFile = false;
try {
reader = new BufferedReader(new FileReader(taskFile));
final XmlPullParser in = Xml.newPullParser();
@@ -183,10 +184,9 @@ public class TaskPersister {
}
XmlUtils.skipCurrentTag(in);
}
- } catch (IOException e) {
- Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e);
- } catch (XmlPullParserException e) {
- Slog.e(TAG, "Unable to parse " + taskFile + ". Error " + e);
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error " + e);
+ deleteFile = true;
} finally {
if (reader != null) {
try {
@@ -194,6 +194,9 @@ public class TaskPersister {
} catch (IOException e) {
}
}
+ if (!DEBUG && deleteFile) {
+ taskFile.delete();
+ }
}
}
@@ -220,7 +223,7 @@ public class TaskPersister {
return new ArrayList<TaskRecord>(Arrays.asList(tasksArray));
}
- private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
+ private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
File file = files[fileNdx];
String filename = file.getName();
@@ -285,8 +288,7 @@ public class TaskPersister {
synchronized(mService) {
final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
persistentTaskIds.clear();
- int taskNdx;
- for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
task = tasks.get(taskNdx);
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
task.isPersistable + " needsPersisting=" + task.needsPersisting);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b94ea62..1b1fc8b 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -259,13 +259,17 @@ abstract public class ManagedServices {
userIds[i]));
}
- ManagedServiceInfo[] toRemove = new ManagedServiceInfo[mServices.size()];
+ ArrayList<ManagedServiceInfo> toRemove = new ArrayList<ManagedServiceInfo>();
final SparseArray<ArrayList<ComponentName>> toAdd
= new SparseArray<ArrayList<ComponentName>>();
synchronized (mMutex) {
- // unbind and remove all existing services
- toRemove = mServices.toArray(toRemove);
+ // Unbind automatically bound services, retain system services.
+ for (ManagedServiceInfo service : mServices) {
+ if (!service.isSystem) {
+ toRemove.add(service);
+ }
+ }
final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>();
final ArraySet<String> newPackages = new ArraySet<String>();
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d81a25e..66cc532 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -46,12 +46,14 @@ import java.util.Map;
* {@hide}
*/
public class NotificationUsageStats {
+ private static final boolean ENABLE_SQLITE_LOG = false;
+
// Guarded by synchronized(this).
private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
private final SQLiteLog mSQLiteLog;
public NotificationUsageStats(Context context) {
- mSQLiteLog = new SQLiteLog(context);
+ mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null;
}
/**
@@ -63,7 +65,9 @@ public class NotificationUsageStats {
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numPostedByApp++;
}
- mSQLiteLog.logPosted(notification);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.logPosted(notification);
+ }
}
/**
@@ -85,7 +89,9 @@ public class NotificationUsageStats {
stats.numRemovedByApp++;
stats.collect(notification.stats);
}
- mSQLiteLog.logRemoved(notification);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.logRemoved(notification);
+ }
}
/**
@@ -97,7 +103,9 @@ public class NotificationUsageStats {
stats.numDismissedByUser++;
stats.collect(notification.stats);
}
- mSQLiteLog.logDismissed(notification);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.logDismissed(notification);
+ }
}
/**
@@ -108,7 +116,9 @@ public class NotificationUsageStats {
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numClickedByUser++;
}
- mSQLiteLog.logClicked(notification);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.logClicked(notification);
+ }
}
/**
@@ -164,7 +174,9 @@ public class NotificationUsageStats {
for (AggregatedStats as : mStats.values()) {
as.dump(pw, indent);
}
- mSQLiteLog.dump(pw, indent);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.dump(pw, indent);
+ }
}
/**
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 157d749..a629a5f 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -139,56 +139,64 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
}
private String[] getExtraPeople(Bundle extras) {
- String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
- if (people != null) {
- return people;
+ Object people = extras.get(Notification.EXTRA_PEOPLE);
+ if (people instanceof String[]) {
+ return (String[]) people;
}
- ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE);
- if (stringArray != null) {
- return (String[]) stringArray.toArray();
+ if (people instanceof ArrayList) {
+ ArrayList arrayList = (ArrayList) people;
+
+ if (arrayList.isEmpty()) {
+ return null;
+ }
+
+ if (arrayList.get(0) instanceof String) {
+ ArrayList<String> stringArray = (ArrayList<String>) arrayList;
+ return stringArray.toArray(new String[stringArray.size()]);
+ }
+
+ if (arrayList.get(0) instanceof CharSequence) {
+ ArrayList<CharSequence> charSeqList = (ArrayList<CharSequence>) arrayList;
+ final int N = charSeqList.size();
+ String[] array = new String[N];
+ for (int i = 0; i < N; i++) {
+ array[i] = charSeqList.get(i).toString();
+ }
+ return array;
+ }
+
+ return null;
}
- String string = extras.getString(Notification.EXTRA_PEOPLE);
- if (string != null) {
- people = new String[1];
- people[0] = string;
- return people;
+ if (people instanceof String) {
+ String[] array = new String[1];
+ array[0] = (String) people;
+ return array;
}
- char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE);
- if (charArray != null) {
- people = new String[1];
- people[0] = new String(charArray);
- return people;
+
+ if (people instanceof char[]) {
+ String[] array = new String[1];
+ array[0] = new String((char[]) people);
+ return array;
}
- CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE);
- if (charSeq != null) {
- people = new String[1];
- people[0] = charSeq.toString();
- return people;
+ if (people instanceof CharSequence) {
+ String[] array = new String[1];
+ array[0] = ((CharSequence) people).toString();
+ return array;
}
- CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE);
- if (charSeqArray != null) {
+ if (people instanceof CharSequence[]) {
+ CharSequence[] charSeqArray = (CharSequence[]) people;
final int N = charSeqArray.length;
- people = new String[N];
+ String[] array = new String[N];
for (int i = 0; i < N; i++) {
- people[i] = charSeqArray[i].toString();
+ array[i] = charSeqArray[i].toString();
}
- return people;
+ return array;
}
- ArrayList<CharSequence> charSeqList =
- extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE);
- if (charSeqList != null) {
- final int N = charSeqList.size();
- people = new String[N];
- for (int i = 0; i < N; i++) {
- people[i] = charSeqList.get(i).toString();
- }
- return people;
- }
return null;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b06b090..d505e81 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11775,8 +11775,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
if (removed.size() > 0) {
- for (int j=0; j<removed.size(); j++) {
- PreferredActivity pa = removed.get(i);
+ for (int r=0; r<removed.size(); r++) {
+ PreferredActivity pa = removed.get(r);
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
pir.removeFilter(pa);
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 6d208ff..80030b4 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -16,12 +16,22 @@
package com.android.server.task;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.task.ITaskManager;
+import android.app.task.Task;
import android.content.Context;
-import android.content.Task;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.util.Log;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
@@ -39,13 +49,6 @@ public class TaskManagerService extends com.android.server.SystemService
/** Master list of tasks. */
private final TaskStore mTasks;
- /** Check the pending queue and start any tasks. */
- static final int MSG_RUN_PENDING = 0;
- /** Initiate the stop task flow. */
- static final int MSG_STOP_TASK = 1;
- /** */
- static final int MSG_CHECK_TASKS = 2;
-
/**
* Track Services that have currently active or pending tasks. The index is provided by
* {@link TaskStatus#getServiceToken()}
@@ -54,6 +57,14 @@ public class TaskManagerService extends com.android.server.SystemService
new SparseArray<TaskServiceContext>();
private final TaskHandler mHandler;
+ private final TaskManagerStub mTaskManagerStub;
+
+ /** Check the pending queue and start any tasks. */
+ static final int MSG_RUN_PENDING = 0;
+ /** Initiate the stop task flow. */
+ static final int MSG_STOP_TASK = 1;
+ /** */
+ static final int MSG_CHECK_TASKS = 2;
private class TaskHandler extends Handler {
@@ -94,21 +105,6 @@ public class TaskManagerService extends com.android.server.SystemService
}
/**
- * Entry point from client to schedule the provided task.
- * This will add the task to the
- * @param task Task object containing execution parameters
- * @param userId The id of the user this task is for.
- * @param uId The package identifier of the application this task is for.
- * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
- * of this task.
- * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
- */
- public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
- TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
- return 0;
- }
-
- /**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
@@ -121,11 +117,42 @@ public class TaskManagerService extends com.android.server.SystemService
super(context);
mTasks = new TaskStore(context);
mHandler = new TaskHandler(context.getMainLooper());
+ mTaskManagerStub = new TaskManagerStub();
}
@Override
public void onStart() {
+ publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
+ }
+
+ /**
+ * Entry point from client to schedule the provided task.
+ * This will add the task to the
+ * @param task Task object containing execution parameters
+ * @param userId The id of the user this task is for.
+ * @param uId The package identifier of the application this task is for.
+ * @param canPersistTask Whether or not the client has the appropriate permissions for
+ * persisting of this task.
+ * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+ */
+ public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+ TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+ return 0;
+ }
+ public List<Task> getPendingTasks(int uid) {
+ ArrayList<Task> outList = new ArrayList<Task>(3);
+ synchronized (mTasks) {
+ final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+ final int N = tasks.size();
+ for (int i = 0; i < N; i++) {
+ TaskStatus ts = tasks.get(i);
+ if (ts.getUid() == uid) {
+ outList.add(ts.getTask());
+ }
+ }
+ }
+ return outList;
}
// StateChangedListener implementations.
@@ -162,7 +189,7 @@ public class TaskManagerService extends com.android.server.SystemService
public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
if (serviceContext == null) {
- Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+ Slog.e(TAG, "Task completed for invalid service context; " + serviceToken);
return;
}
@@ -203,4 +230,98 @@ public class TaskManagerService extends com.android.server.SystemService
private void postCheckTasksMessage() {
mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
}
+
+ /**
+ * Binder stub trampoline implementation
+ */
+ final class TaskManagerStub extends ITaskManager.Stub {
+ /** Cache determination of whether a given app can persist tasks
+ * key is uid of the calling app; value is undetermined/true/false
+ */
+ private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
+
+ // Determine whether the caller is allowed to persist tasks, with a small cache
+ // because the lookup is expensive enough that we'd like to avoid repeating it.
+ // This must be called from within the calling app's binder identity!
+ private boolean canCallerPersistTasks() {
+ final boolean canPersist;
+ final int callingUid = Binder.getCallingUid();
+ synchronized (mPersistCache) {
+ Boolean cached = mPersistCache.get(callingUid);
+ if (cached) {
+ canPersist = cached.booleanValue();
+ } else {
+ // Persisting tasks is tantamount to running at boot, so we permit
+ // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+ // permission
+ int result = getContext().checkCallingPermission(
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
+ canPersist = (result == PackageManager.PERMISSION_GRANTED);
+ mPersistCache.put(callingUid, canPersist);
+ }
+ }
+ return canPersist;
+ }
+
+ // ITaskManager implementation
+ @Override
+ public int schedule(Task task) throws RemoteException {
+ final boolean canPersist = canCallerPersistTasks();
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getCallingUserId();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return TaskManagerService.this.schedule(task, userId, uid, canPersist);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public List<Task> getAllPendingTasks() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void cancelAll() throws RemoteException {
+ }
+
+ @Override
+ public void cancel(int taskId) throws RemoteException {
+ }
+
+ /**
+ * "dumpsys" infrastructure
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ long identityToken = Binder.clearCallingIdentity();
+ try {
+ TaskManagerService.this.dumpInternal(pw);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+ };
+
+ void dumpInternal(PrintWriter pw) {
+ synchronized (mTasks) {
+ pw.print("Registered tasks:");
+ if (mTasks.size() > 0) {
+ SparseArray<TaskStatus> tasks = mTasks.getTasks();
+ for (int i = 0; i < tasks.size(); i++) {
+ TaskStatus ts = tasks.get(i);
+ pw.println();
+ ts.dump(pw, " ");
+ }
+ } else {
+ pw.println();
+ pw.println("No tasks scheduled.");
+ }
+ }
+ pw.println();
+ }
}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index b51cbb3..165445a 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -45,7 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* is reused to start concurrent tasks on the TaskService. Information here is unique
* to the service.
* Functionality provided by this class:
- * - Managages wakelock for the service.
+ * - Manages wakelock for the service.
* - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
* -
*/
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
index 3bfc8a5..81187c8 100644
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -16,8 +16,8 @@
package com.android.server.task;
+import android.app.task.Task;
import android.content.Context;
-import android.content.Task;
import android.util.SparseArray;
import com.android.server.task.controllers.TaskStatus;
@@ -95,6 +95,13 @@ public class TaskStore {
}
/**
+ * @return the number of tasks in the store
+ */
+ public int size() {
+ return mTasks.size();
+ }
+
+ /**
* @return The live array of TaskStatus objects.
*/
public SparseArray<TaskStatus> getTasks() {
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 6a4e1f3..a0038c5 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -70,13 +70,10 @@ public class ConnectivityController extends StateController {
}
/**
- * @param userId Id of the user for whom we are updating the connectivity state.
+ *
*/
- private void updateTrackedTasks(int userId) {
+ private void updateTrackedTasks() {
for (TaskStatus ts : mTrackedTasks) {
- if (ts.userId != userId) {
- continue;
- }
boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
@@ -107,14 +104,13 @@ public class ConnectivityController extends StateController {
final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
// This broadcast gets sent a lot, only update if the active network has changed.
if (activeNetwork.getType() == networkType) {
- final int userid = context.getUserId();
mMetered = false;
mConnectivity =
!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (mConnectivity) { // No point making the call if we know there's no conn.
mMetered = connManager.isActiveNetworkMetered();
}
- updateTrackedTasks(userid);
+ updateTrackedTasks();
}
} else {
Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index d96fedc..d270016 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -16,17 +16,19 @@
package com.android.server.task.controllers;
+import android.app.task.Task;
import android.content.ComponentName;
-import android.content.Task;
import android.content.pm.PackageParser;
import android.os.Bundle;
import android.os.SystemClock;
+import android.os.UserHandle;
+import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Uniquely identifies a task internally.
- * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
* Contains current state of the requirements of the task, as well as a function to evaluate
* whether it's ready to run.
* This object is shared among the various controllers - hence why the different fields are atomic.
@@ -36,10 +38,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @hide
*/
public class TaskStatus {
+ final Task task;
final int taskId;
- final int userId;
final int uId;
- final ComponentName component;
final Bundle extras;
final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
@@ -57,9 +58,9 @@ public class TaskStatus {
private long earliestRunTimeElapsedMillis;
private long latestRunTimeElapsedMillis;
- /** Provide a unique handle to the service that this task will be run on. */
+ /** Provide a handle to the service that this task will be run on. */
public int getServiceToken() {
- return component.hashCode() + userId;
+ return uId;
}
/** Generate a TaskStatus object for a given task and uid. */
@@ -70,9 +71,8 @@ public class TaskStatus {
/** Set up the state of a newly scheduled task. */
TaskStatus(Task task, int userId, int uId) {
+ this.task = task;
this.taskId = task.getTaskId();
- this.userId = userId;
- this.component = task.getService();
this.extras = task.getExtras();
this.uId = uId;
@@ -100,16 +100,20 @@ public class TaskStatus {
hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
}
+ public Task getTask() {
+ return task;
+ }
+
public int getTaskId() {
return taskId;
}
public ComponentName getServiceComponent() {
- return component;
+ return task.getService();
}
public int getUserId() {
- return userId;
+ return UserHandle.getUserId(uId);
}
public int getUid() {
@@ -161,9 +165,9 @@ public class TaskStatus {
@Override
public int hashCode() {
- int result = component.hashCode();
+ int result = getServiceComponent().hashCode();
result = 31 * result + taskId;
- result = 31 * result + userId;
+ result = 31 * result + uId;
return result;
}
@@ -174,7 +178,14 @@ public class TaskStatus {
TaskStatus that = (TaskStatus) o;
return ((taskId == that.taskId)
- && (userId == that.userId)
- && (component.equals(that.component)));
+ && (uId == that.uId)
+ && (getServiceComponent().equals(that.getServiceComponent())));
+ }
+
+ // Dumpsys infrastructure
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("Task "); pw.println(taskId);
+ pw.print(prefix); pw.print("uid="); pw.println(uId);
+ pw.print(prefix); pw.print("component="); pw.println(task.getService());
}
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 47ce3b6..f18939f 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -63,6 +63,11 @@ public class TrustAgentWrapper {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_GRANT_TRUST:
+ if (!isConnected()) {
+ Log.w(TAG, "Agent is not connected, cannot grant trust: "
+ + mName.flattenToShortString());
+ return;
+ }
mTrusted = true;
mMessage = (CharSequence) msg.obj;
boolean initiatedByUser = msg.arg1 != 0;
@@ -119,6 +124,7 @@ public class TrustAgentWrapper {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
+ mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
setCallback(mCallback);
}
@@ -179,7 +185,10 @@ public class TrustAgentWrapper {
public void unbind() {
if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
+ mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
mContext.unbindService(mConnection);
+ mTrustAgentService = null;
+ mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
}
public boolean isConnected() {
diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java
index aad156c..56950d2 100644
--- a/services/core/java/com/android/server/trust/TrustArchive.java
+++ b/services/core/java/com/android/server/trust/TrustArchive.java
@@ -33,6 +33,8 @@ public class TrustArchive {
private static final int TYPE_REVOKE_TRUST = 1;
private static final int TYPE_TRUST_TIMEOUT = 2;
private static final int TYPE_AGENT_DIED = 3;
+ private static final int TYPE_AGENT_CONNECTED = 4;
+ private static final int TYPE_AGENT_STOPPED = 5;
private static final int HISTORY_LIMIT = 200;
@@ -79,6 +81,14 @@ public class TrustArchive {
addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false));
}
+ public void logAgentConnected(int userId, ComponentName agent) {
+ addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, false));
+ }
+
+ public void logAgentStopped(int userId, ComponentName agent) {
+ addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, false));
+ }
+
private void addEvent(Event e) {
if (mEvents.size() >= HISTORY_LIMIT) {
mEvents.removeFirst();
@@ -152,6 +162,10 @@ public class TrustArchive {
return "TrustTimeout";
case TYPE_AGENT_DIED:
return "AgentDied";
+ case TYPE_AGENT_CONNECTED:
+ return "AgentConnected";
+ case TYPE_AGENT_STOPPED:
+ return "AgentStopped";
default:
return "Unknown(" + type + ")";
}
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
new file mode 100644
index 0000000..4bdd2be
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 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.server.tv;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.tv.TvInputHardwareInfo;
+import android.tv.TvStreamConfig;
+import android.view.Surface;
+
+/**
+ * Provides access to the low-level TV input hardware abstraction layer.
+ */
+final class TvInputHal {
+ public final static int SUCCESS = 0;
+ public final static int ERROR_NO_INIT = -1;
+ public final static int ERROR_STALE_CONFIG = -2;
+ public final static int ERROR_UNKNOWN = -3;
+
+ public static final int TYPE_HDMI = 1;
+ public static final int TYPE_BUILT_IN_TUNER = 2;
+ public static final int TYPE_PASSTHROUGH = 3;
+
+ public interface Callback {
+ public void onDeviceAvailable(
+ TvInputHardwareInfo info, TvStreamConfig[] configs);
+ public void onDeviceUnavailable(int deviceId);
+ public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+ }
+
+ private native long nativeOpen();
+
+ private static native int nativeSetSurface(long ptr, int deviceId, int streamId,
+ Surface surface);
+ private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
+ int generation);
+ private static native void nativeClose(long ptr);
+
+ private long mPtr = 0l;
+ private final Callback mCallback;
+ private final HandlerThread mThread = new HandlerThread("TV input HAL event thread");
+ private final Handler mHandler;
+ private int mStreamConfigGeneration = 0;
+ private TvStreamConfig[] mStreamConfigs;
+
+ public TvInputHal(Callback callback) {
+ mCallback = callback;
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper());
+ }
+
+ public void init() {
+ mPtr = nativeOpen();
+ }
+
+ public int setSurface(int deviceId, Surface surface, TvStreamConfig streamConfig) {
+ if (mPtr == 0) {
+ return ERROR_NO_INIT;
+ }
+ if (mStreamConfigGeneration != streamConfig.getGeneration()) {
+ return ERROR_STALE_CONFIG;
+ }
+ if (nativeSetSurface(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+ return SUCCESS;
+ } else {
+ return ERROR_UNKNOWN;
+ }
+ }
+
+ public void close() {
+ if (mPtr != 0l) {
+ nativeClose(mPtr);
+ mThread.quitSafely();
+ }
+ }
+
+ private synchronized void retrieveStreamConfigs(int deviceId) {
+ ++mStreamConfigGeneration;
+ mStreamConfigs = nativeGetStreamConfigs(mPtr, deviceId, mStreamConfigGeneration);
+ }
+
+ // Called from native
+ private void deviceAvailableFromNative(int deviceId, int type) {
+ final TvInputHardwareInfo info = new TvInputHardwareInfo(deviceId, type);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ retrieveStreamConfigs(info.getDeviceId());
+ mCallback.onDeviceAvailable(info, mStreamConfigs);
+ }
+ });
+ }
+
+ private void deviceUnavailableFromNative(int deviceId) {
+ final int id = deviceId;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onDeviceUnavailable(id);
+ }
+ });
+ }
+
+ private void streamConfigsChangedFromNative(int deviceId) {
+ final int id = deviceId;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ retrieveStreamConfigs(id);
+ mCallback.onStreamConfigurationChanged(id, mStreamConfigs);
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
new file mode 100644
index 0000000..b95b0f0
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2014 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.server.tv;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.tv.ITvInputHardware;
+import android.tv.ITvInputHardwareCallback;
+import android.tv.TvInputHardwareInfo;
+import android.tv.TvStreamConfig;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A helper class for TvInputManagerService to handle TV input hardware.
+ *
+ * This class does a basic connection management and forwarding calls to TvInputHal which eventually
+ * calls to tv_input HAL module.
+ *
+ * @hide
+ */
+class TvInputHardwareManager implements TvInputHal.Callback {
+ private static final String TAG = TvInputHardwareManager.class.getSimpleName();
+ private final TvInputHal mHal = new TvInputHal(this);
+ private final SparseArray<Connection> mConnections = new SparseArray<Connection>();
+ private final List<TvInputHardwareInfo> mInfoList = new ArrayList<TvInputHardwareInfo>();
+ private final Context mContext;
+ private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
+
+ private final Object mLock = new Object();
+
+ public TvInputHardwareManager(Context context) {
+ mContext = context;
+ // TODO(hdmi): mHdmiManager = mContext.getSystemService(...);
+ // TODO(hdmi): mHdmiClient = mHdmiManager.getTvClient();
+ mHal.init();
+ }
+
+ @Override
+ public void onDeviceAvailable(
+ TvInputHardwareInfo info, TvStreamConfig[] configs) {
+ synchronized (mLock) {
+ Connection connection = new Connection(info);
+ connection.updateConfigsLocked(configs);
+ mConnections.put(info.getDeviceId(), connection);
+ buildInfoListLocked();
+ // TODO: notify if necessary
+ }
+ }
+
+ private void buildInfoListLocked() {
+ mInfoList.clear();
+ for (int i = 0; i < mConnections.size(); ++i) {
+ mInfoList.add(mConnections.valueAt(i).getInfoLocked());
+ }
+ }
+
+ @Override
+ public void onDeviceUnavailable(int deviceId) {
+ synchronized (mLock) {
+ Connection connection = mConnections.get(deviceId);
+ if (connection == null) {
+ Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
+ return;
+ }
+ connection.resetLocked(null, null, null, null);
+ mConnections.remove(deviceId);
+ buildInfoListLocked();
+ // TODO: notify if necessary
+ }
+ }
+
+ @Override
+ public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
+ synchronized (mLock) {
+ Connection connection = mConnections.get(deviceId);
+ if (connection == null) {
+ Slog.e(TAG, "StreamConfigurationChanged: Cannot find a connection with "
+ + deviceId);
+ return;
+ }
+ connection.updateConfigsLocked(configs);
+ try {
+ connection.getCallbackLocked().onStreamConfigChanged(configs);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "onStreamConfigurationChanged: " + e);
+ }
+ }
+ }
+
+ public List<TvInputHardwareInfo> getHardwareList() {
+ synchronized (mLock) {
+ return mInfoList;
+ }
+ }
+
+ /**
+ * Create a TvInputHardware object with a specific deviceId. One service at a time can access
+ * the object, and if more than one process attempts to create hardware with the same deviceId,
+ * the latest service will get the object and all the other hardware are released. The
+ * release is notified via ITvInputHardwareCallback.onReleased().
+ */
+ public ITvInputHardware acquireHardware(int deviceId, ITvInputHardwareCallback callback,
+ int callingUid, int resolvedUserId) {
+ if (callback == null) {
+ throw new NullPointerException();
+ }
+ synchronized (mLock) {
+ Connection connection = mConnections.get(deviceId);
+ if (connection == null) {
+ Slog.e(TAG, "Invalid deviceId : " + deviceId);
+ return null;
+ }
+ if (connection.getCallingUidLocked() != callingUid
+ || connection.getResolvedUserIdLocked() != resolvedUserId) {
+ TvInputHardwareImpl hardware = new TvInputHardwareImpl(connection.getInfoLocked());
+ try {
+ callback.asBinder().linkToDeath(connection, 0);
+ } catch (RemoteException e) {
+ hardware.release();
+ return null;
+ }
+ connection.resetLocked(hardware, callback, callingUid, resolvedUserId);
+ }
+ return connection.getHardwareLocked();
+ }
+ }
+
+ /**
+ * Release the specified hardware.
+ */
+ public void releaseHardware(int deviceId, ITvInputHardware hardware, int callingUid,
+ int resolvedUserId) {
+ synchronized (mLock) {
+ Connection connection = mConnections.get(deviceId);
+ if (connection == null) {
+ Slog.e(TAG, "Invalid deviceId : " + deviceId);
+ return;
+ }
+ if (connection.getHardwareLocked() != hardware
+ || connection.getCallingUidLocked() != callingUid
+ || connection.getResolvedUserIdLocked() != resolvedUserId) {
+ return;
+ }
+ connection.resetLocked(null, null, null, null);
+ }
+ }
+
+ private class Connection implements IBinder.DeathRecipient {
+ private final TvInputHardwareInfo mInfo;
+ private TvInputHardwareImpl mHardware = null;
+ private ITvInputHardwareCallback mCallback;
+ private TvStreamConfig[] mConfigs = null;
+ private Integer mCallingUid = null;
+ private Integer mResolvedUserId = null;
+
+ public Connection(TvInputHardwareInfo info) {
+ mInfo = info;
+ }
+
+ // *Locked methods assume TvInputHardwareManager.mLock is held.
+
+ public void resetLocked(TvInputHardwareImpl hardware,
+ ITvInputHardwareCallback callback, Integer callingUid, Integer resolvedUserId) {
+ if (mHardware != null) {
+ try {
+ mCallback.onReleased();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Connection::resetHardware: " + e);
+ }
+ mHardware.release();
+ }
+ mHardware = hardware;
+ mCallback = callback;
+ mCallingUid = callingUid;
+ mResolvedUserId = resolvedUserId;
+
+ if (mHardware != null && mCallback != null) {
+ try {
+ mCallback.onStreamConfigChanged(getConfigsLocked());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Connection::resetHardware: " + e);
+ }
+ }
+ }
+
+ public void updateConfigsLocked(TvStreamConfig[] configs) {
+ mConfigs = configs;
+ }
+
+ public TvInputHardwareInfo getInfoLocked() {
+ return mInfo;
+ }
+
+ public ITvInputHardware getHardwareLocked() {
+ return mHardware;
+ }
+
+ public ITvInputHardwareCallback getCallbackLocked() {
+ return mCallback;
+ }
+
+ public TvStreamConfig[] getConfigsLocked() {
+ return mConfigs;
+ }
+
+ public int getCallingUidLocked() {
+ return mCallingUid;
+ }
+
+ public int getResolvedUserIdLocked() {
+ return mResolvedUserId;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ resetLocked(null, null, null, null);
+ }
+ }
+ }
+
+ private class TvInputHardwareImpl extends ITvInputHardware.Stub {
+ private final TvInputHardwareInfo mInfo;
+ private boolean mReleased = false;
+ private final Object mImplLock = new Object();
+
+ public TvInputHardwareImpl(TvInputHardwareInfo info) {
+ mInfo = info;
+ }
+
+ public void release() {
+ synchronized (mImplLock) {
+ mReleased = true;
+ }
+ }
+
+ @Override
+ public boolean setSurface(Surface surface, TvStreamConfig config)
+ throws RemoteException {
+ synchronized (mImplLock) {
+ if (mReleased) {
+ throw new IllegalStateException("Device already released.");
+ }
+ if (mInfo.getType() == TvInputHal.TYPE_HDMI) {
+ if (surface != null) {
+ // Set "Active Source" for HDMI.
+ // TODO(hdmi): mHdmiClient.deviceSelect(...);
+ mActiveHdmiSources.add(mInfo.getDeviceId());
+ } else {
+ mActiveHdmiSources.remove(mInfo.getDeviceId());
+ if (mActiveHdmiSources.size() == 0) {
+ // Tell HDMI that no HDMI source is active
+ // TODO(hdmi): mHdmiClient.portSelect(null);
+ }
+ }
+ }
+ return mHal.setSurface(mInfo.getDeviceId(), surface, config) == TvInputHal.SUCCESS;
+ }
+ }
+
+ @Override
+ public void setVolume(float volume) throws RemoteException {
+ synchronized (mImplLock) {
+ if (mReleased) {
+ throw new IllegalStateException("Device already released.");
+ }
+ }
+ // TODO
+ }
+
+ @Override
+ public boolean dispatchKeyEventToHdmi(KeyEvent event) throws RemoteException {
+ synchronized (mImplLock) {
+ if (mReleased) {
+ throw new IllegalStateException("Device already released.");
+ }
+ }
+ if (mInfo.getType() != TvInputHal.TYPE_HDMI) {
+ return false;
+ }
+ // TODO(hdmi): mHdmiClient.sendKeyEvent(event);
+ return false;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 8ad7fff..6c38a4c 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -42,11 +42,14 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.TvContract;
import android.tv.ITvInputClient;
+import android.tv.ITvInputHardware;
+import android.tv.ITvInputHardwareCallback;
import android.tv.ITvInputManager;
import android.tv.ITvInputService;
import android.tv.ITvInputServiceCallback;
import android.tv.ITvInputSession;
import android.tv.ITvInputSessionCallback;
+import android.tv.TvInputHardwareInfo;
import android.tv.TvInputInfo;
import android.tv.TvInputService;
import android.util.Slog;
@@ -71,6 +74,7 @@ public final class TvInputManagerService extends SystemService {
private static final String TAG = "TvInputManagerService";
private final Context mContext;
+ private final TvInputHardwareManager mTvInputHardwareManager;
private final ContentResolver mContentResolver;
@@ -92,6 +96,7 @@ public final class TvInputManagerService extends SystemService {
mContentResolver = context.getContentResolver();
mLogHandler = new LogHandler(IoThread.get().getLooper());
+ mTvInputHardwareManager = new TvInputHardwareManager(context);
registerBroadcastReceivers();
synchronized (mLock) {
@@ -730,6 +735,64 @@ public final class TvInputManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
+ if (mContext.checkCallingPermission(
+ android.Manifest.permission.TV_INPUT_HARDWARE)
+ != PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mTvInputHardwareManager.getHardwareList();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public ITvInputHardware acquireTvInputHardware(int deviceId,
+ ITvInputHardwareCallback callback, int userId) throws RemoteException {
+ if (mContext.checkCallingPermission(
+ android.Manifest.permission.TV_INPUT_HARDWARE)
+ != PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "acquireTvInputHardware");
+ try {
+ return mTvInputHardwareManager.acquireHardware(
+ deviceId, callback, callingUid, resolvedUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
+ throws RemoteException {
+ if (mContext.checkCallingPermission(
+ android.Manifest.permission.TV_INPUT_HARDWARE)
+ != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "releaseTvInputHardware");
+ try {
+ mTvInputHardwareManager.releaseHardware(
+ deviceId, hardware, callingUid, resolvedUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
private static final class UserState {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e2d2ac6..4f8b9d7 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -24,9 +24,7 @@ import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
import android.os.IRemoteCallback;
-import android.os.SystemProperties;
import android.util.Slog;
-import android.view.View;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -299,7 +297,7 @@ public class AppTransition implements Dump {
return null;
}
- Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
+ Animation loadAnimationAttr(WindowManager.LayoutParams lp, int animAttr) {
int anim = 0;
Context context = mContext;
if (animAttr >= 0) {
@@ -315,7 +313,19 @@ public class AppTransition implements Dump {
return null;
}
- private Animation loadAnimation(String packageName, int resId) {
+ Animation loadAnimationRes(WindowManager.LayoutParams lp, int resId) {
+ Context context = mContext;
+ if (resId >= 0) {
+ AttributeCache.Entry ent = getCachedAnimations(lp);
+ if (ent != null) {
+ context = ent.context;
+ }
+ return AnimationUtils.loadAnimation(context, resId);
+ }
+ return null;
+ }
+
+ private Animation loadAnimationRes(String packageName, int resId) {
int anim = 0;
Context context = mContext;
if (resId >= 0) {
@@ -695,11 +705,31 @@ public class AppTransition implements Dump {
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- int appWidth, int appHeight, int orientation,
- Rect containingFrame, Rect contentInsets, boolean isFullScreen) {
+ int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
+ boolean isFullScreen, boolean isVoiceInteraction) {
Animation a;
- if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
- a = loadAnimation(mNextAppTransitionPackage, enter ?
+ if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
+ || transit == TRANSIT_TASK_OPEN
+ || transit == TRANSIT_TASK_TO_FRONT)) {
+ a = loadAnimationRes(lp, enter
+ ? com.android.internal.R.anim.voice_activity_open_enter
+ : com.android.internal.R.anim.voice_activity_open_exit);
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+ "applyAnimation voice:"
+ + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
+ + " Callers=" + Debug.getCallers(3));
+ } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
+ || transit == TRANSIT_TASK_CLOSE
+ || transit == TRANSIT_TASK_TO_BACK)) {
+ a = loadAnimationRes(lp, enter
+ ? com.android.internal.R.anim.voice_activity_close_enter
+ : com.android.internal.R.anim.voice_activity_close_exit);
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+ "applyAnimation voice:"
+ + " anim=" + a + " transit=" + transit + " isEntrance=" + enter
+ + " Callers=" + Debug.getCallers(3));
+ } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
+ a = loadAnimationRes(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation:"
@@ -782,7 +812,7 @@ public class AppTransition implements Dump {
: WindowAnimation_wallpaperIntraCloseExitAnimation;
break;
}
- a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
+ a = animAttr != 0 ? loadAnimationAttr(lp, animAttr) : null;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation:"
+ " anim=" + a
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ca4ad8a..12c15e2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,8 @@ class AppWindowToken extends WindowToken {
final WindowAnimator mAnimator;
+ final boolean voiceInteraction;
+
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -107,11 +109,13 @@ class AppWindowToken extends WindowToken {
boolean mDeferRemoval;
- AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
+ AppWindowToken(WindowManagerService _service, IApplicationToken _token,
+ boolean _voiceInteraction) {
super(_service, _token.asBinder(),
WindowManager.LayoutParams.TYPE_APPLICATION, true);
appWindowToken = this;
appToken = _token;
+ voiceInteraction = _voiceInteraction;
mInputApplicationHandle = new InputApplicationHandle(this);
mAnimator = service.mAnimator;
mAppAnimator = new AppWindowAnimator(this);
@@ -249,7 +253,7 @@ class AppWindowToken extends WindowToken {
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
- pw.print(prefix); pw.println("app=true");
+ pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
}
if (allAppWindows.size() > 0) {
pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 27ab5ac..9937321 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2215,6 +2215,11 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ if (type == TYPE_VOICE_INTERACTION) {
+ Slog.w(TAG, "Attempted to add voice interaction window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
if (type == TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
@@ -2250,6 +2255,12 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_VOICE_INTERACTION) {
+ if (token.windowType != TYPE_VOICE_INTERACTION) {
+ Slog.w(TAG, "Attempted to add voice interaction window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
} else if (type == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with bad token "
@@ -3173,7 +3184,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
private boolean applyAnimationLocked(AppWindowToken atoken,
- WindowManager.LayoutParams lp, int transit, boolean enter) {
+ WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) {
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
@@ -3189,6 +3200,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState win = atoken.findMainWindow();
Rect containingFrame = new Rect(0, 0, width, height);
Rect contentInsets = new Rect();
+ boolean isFullScreen = true;
if (win != null) {
if (win.mContainingFrame != null) {
containingFrame.set(win.mContainingFrame);
@@ -3196,13 +3208,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.mContentInsets != null) {
contentInsets.set(win.mContentInsets);
}
+ isFullScreen =
+ ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) ==
+ SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
}
- boolean isFullScreen =
- ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
- == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN);
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen);
+ mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen,
+ isVoiceInteraction);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -3422,7 +3435,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
- int configChanges) {
+ int configChanges, boolean voiceInteraction) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3448,7 +3461,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.w(TAG, "Attempted to add existing app token: " + token);
return;
}
- atoken = new AppWindowToken(this, token);
+ atoken = new AppWindowToken(this, token, voiceInteraction);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = taskId;
atoken.appFullscreen = fullscreen;
@@ -4200,7 +4213,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
- boolean visible, int transit, boolean performLayout) {
+ boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
boolean delayed = false;
if (wtoken.clientHidden == visible) {
@@ -4221,7 +4234,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
wtoken.mAppAnimator.animation = null;
}
- if (applyAnimationLocked(wtoken, lp, transit, visible)) {
+ if (applyAnimationLocked(wtoken, lp, transit, visible, isVoiceInteraction)) {
delayed = runningAppAnimation = true;
}
WindowState window = wtoken.findMainWindow();
@@ -4399,7 +4412,7 @@ public class WindowManagerService extends IWindowManager.Stub
final long origId = Binder.clearCallingIdentity();
setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,
- true);
+ true, wtoken.voiceInteraction);
wtoken.updateReportedVisibilityLocked();
Binder.restoreCallingIdentity(origId);
}
@@ -4546,7 +4559,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
delayed = setTokenVisibilityLocked(wtoken, null, false,
- AppTransition.TRANSIT_UNSET, true);
+ AppTransition.TRANSIT_UNSET, true, wtoken.voiceInteraction);
wtoken.inPendingTransaction = false;
mOpeningApps.remove(wtoken);
wtoken.waitingToShow = false;
@@ -8537,6 +8550,7 @@ public class WindowManagerService extends IWindowManager.Stub
LayoutParams animLp = null;
int bestAnimLayer = -1;
boolean fullscreenAnim = false;
+ boolean voiceInteraction = false;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + mWallpaperTarget
@@ -8581,6 +8595,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ voiceInteraction |= wtoken.voiceInteraction;
+
if (wtoken.appFullscreen) {
WindowState ws = wtoken.findMainWindow();
if (ws != null) {
@@ -8653,7 +8669,7 @@ public class WindowManagerService extends IWindowManager.Stub
appAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
appAnimator.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, true, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
@@ -8685,7 +8701,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
- setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
+ setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c88382c..4a80e3e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -714,6 +714,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mAppToken != null ? mAppToken.appToken : null;
}
+ @Override
+ public boolean isVoiceInteraction() {
+ return mAppToken != null ? mAppToken.voiceInteraction : false;
+ }
+
boolean setInsetsChanged() {
mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1e79dcb..e257ebc 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1658,7 +1658,7 @@ class WindowStateAnimator {
break;
}
if (attr >= 0) {
- a = mService.mAppTransition.loadAnimation(mWin.mAttrs, attr);
+ a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr);
}
}
if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 51583a5..3cfb45b 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -23,6 +23,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
$(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
$(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
new file mode 100644
index 0000000..f0c4f3a
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2014 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.
+ */
+
+#define LOG_TAG "TvInputHal"
+
+//#define LOG_NDEBUG 0
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <gui/Surface.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <hardware/tv_input.h>
+
+namespace android {
+
+static struct {
+ jmethodID deviceAvailable;
+ jmethodID deviceUnavailable;
+ jmethodID streamConfigsChanged;
+} gTvInputHalClassInfo;
+
+static struct {
+ jclass clazz;
+} gTvStreamConfigClassInfo;
+
+static struct {
+ jclass clazz;
+
+ jmethodID constructor;
+ jmethodID streamId;
+ jmethodID type;
+ jmethodID maxWidth;
+ jmethodID maxHeight;
+ jmethodID generation;
+ jmethodID build;
+} gTvStreamConfigBuilderClassInfo;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class JTvInputHal {
+public:
+ ~JTvInputHal();
+
+ static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
+
+ int setSurface(int deviceId, int streamId, const sp<Surface>& surface);
+ void getStreamConfigs(int deviceId, jobjectArray* array);
+ const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
+
+private:
+ class Connection {
+ public:
+ Connection() : mStreamId(0) {}
+
+ sp<Surface> mSurface;
+ sp<NativeHandle> mSourceHandle;
+ int mStreamId;
+ };
+
+ JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev);
+
+ static void notify(
+ tv_input_device_t* dev,tv_input_event_t* event, void* data);
+
+ void onDeviceAvailable(const tv_input_device_info_t& info);
+ void onDeviceUnavailable(int deviceId);
+ void onStreamConfigurationsChanged(int deviceId);
+
+ jweak mThiz;
+ tv_input_device_t* mDevice;
+ tv_input_callback_ops_t mCallback;
+
+ KeyedVector<int, Connection> mConnections;
+};
+
+JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) {
+ mThiz = env->NewWeakGlobalRef(thiz);
+ mDevice = device;
+ mCallback.notify = &JTvInputHal::notify;
+
+ mDevice->initialize(mDevice, &mCallback, this);
+}
+
+JTvInputHal::~JTvInputHal() {
+ mDevice->common.close((hw_device_t*)mDevice);
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mThiz);
+ mThiz = NULL;
+}
+
+JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
+ tv_input_module_t* module = NULL;
+ status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&module);
+ if (err) {
+ ALOGE("Couldn't load %s module (%s)",
+ TV_INPUT_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ tv_input_device_t* device = NULL;
+ err = module->common.methods->open(
+ (hw_module_t*)module,
+ TV_INPUT_DEFAULT_DEVICE,
+ (hw_device_t**)&device);
+ if (err) {
+ ALOGE("Couldn't open %s device (%s)",
+ TV_INPUT_DEFAULT_DEVICE, strerror(-err));
+ return 0;
+ }
+
+ return new JTvInputHal(env, thiz, device);
+}
+
+int JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surface) {
+ Connection& connection = mConnections.editValueFor(deviceId);
+ if (connection.mStreamId == streamId && connection.mSurface == surface) {
+ // Nothing to do
+ return NO_ERROR;
+ }
+ if (Surface::isValid(connection.mSurface)) {
+ connection.mSurface.clear();
+ }
+ if (surface == NULL) {
+ if (connection.mSurface != NULL) {
+ connection.mSurface->setSidebandStream(NULL);
+ connection.mSurface.clear();
+ }
+ if (connection.mSourceHandle != NULL) {
+ // Need to reset streams
+ if (mDevice->close_stream(
+ mDevice, deviceId, connection.mStreamId) != 0) {
+ ALOGE("Couldn't remove stream");
+ return BAD_VALUE;
+ }
+ connection.mSourceHandle.clear();
+ }
+ return NO_ERROR;
+ }
+ connection.mSurface = surface;
+ if (connection.mSourceHandle == NULL) {
+ // Need to configure stream
+ int numConfigs = 0;
+ const tv_stream_config_t* configs = NULL;
+ if (mDevice->get_stream_configurations(
+ mDevice, deviceId, &numConfigs, &configs) != 0) {
+ ALOGE("Couldn't get stream configs");
+ return UNKNOWN_ERROR;
+ }
+ int configIndex = -1;
+ for (int i = 0; i < numConfigs; ++i) {
+ if (configs[i].stream_id == streamId) {
+ configIndex = i;
+ break;
+ }
+ }
+ if (configIndex == -1) {
+ ALOGE("Cannot find a config with given stream ID: %d", streamId);
+ return BAD_VALUE;
+ }
+ // TODO: handle buffer producer profile.
+ if (configs[configIndex].type !=
+ TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
+ ALOGE("Profiles other than independent video source is not yet "
+ "supported : type = %d", configs[configIndex].type);
+ return INVALID_OPERATION;
+ }
+ tv_stream_t stream;
+ stream.stream_id = configs[configIndex].stream_id;
+ if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
+ ALOGE("Couldn't add stream");
+ return UNKNOWN_ERROR;
+ }
+ connection.mSourceHandle = NativeHandle::create(
+ stream.sideband_stream_source_handle, false);
+ connection.mStreamId = stream.stream_id;
+ connection.mSurface->setSidebandStream(connection.mSourceHandle);
+ }
+ return NO_ERROR;
+}
+
+const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
+ const tv_stream_config_t* configs = NULL;
+ if (mDevice->get_stream_configurations(
+ mDevice, deviceId, numConfigs, &configs) != 0) {
+ ALOGE("Couldn't get stream configs");
+ return NULL;
+ }
+ return configs;
+}
+
+
+// static
+void JTvInputHal::notify(
+ tv_input_device_t* dev, tv_input_event_t* event, void* data) {
+ JTvInputHal* thiz = (JTvInputHal*)data;
+ switch (event->type) {
+ case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
+ thiz->onDeviceAvailable(event->device_info);
+ } break;
+ case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
+ thiz->onDeviceUnavailable(event->device_info.device_id);
+ } break;
+ case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
+ thiz->onStreamConfigurationsChanged(event->device_info.device_id);
+ } break;
+ default:
+ ALOGE("Unrecognizable event");
+ }
+}
+
+void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ mConnections.add(info.device_id, Connection());
+ env->CallVoidMethod(
+ mThiz,
+ gTvInputHalClassInfo.deviceAvailable,
+ info.device_id,
+ info.type);
+}
+
+void JTvInputHal::onDeviceUnavailable(int deviceId) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ mConnections.removeItem(deviceId);
+ env->CallVoidMethod(
+ mThiz,
+ gTvInputHalClassInfo.deviceUnavailable,
+ deviceId);
+}
+
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ mConnections.removeItem(deviceId);
+ env->CallVoidMethod(
+ mThiz,
+ gTvInputHalClassInfo.streamConfigsChanged,
+ deviceId);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static jlong nativeOpen(JNIEnv* env, jobject thiz) {
+ return (jlong)JTvInputHal::createInstance(env, thiz);
+}
+
+static int nativeSetSurface(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
+ JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+ sp<Surface> surface(
+ jsurface
+ ? android_view_Surface_getSurface(env, jsurface)
+ : NULL);
+ return tvInputHal->setSurface(deviceId, streamId, surface);
+}
+
+static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
+ jlong ptr, jint deviceId, jint generation) {
+ JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+ int numConfigs = 0;
+ const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
+
+ jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
+ for (int i = 0; i < numConfigs; ++i) {
+ jobject builder = env->NewObject(
+ gTvStreamConfigBuilderClassInfo.clazz,
+ gTvStreamConfigBuilderClassInfo.constructor);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.generation, generation);
+
+ jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
+
+ env->SetObjectArrayElement(result, i, config);
+
+ env->DeleteLocalRef(config);
+ env->DeleteLocalRef(builder);
+ }
+ return result;
+}
+
+static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
+ JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+ delete tvInputHal;
+}
+
+static JNINativeMethod gTvInputHalMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeOpen", "()J",
+ (void*) nativeOpen },
+ { "nativeSetSurface", "(JIILandroid/view/Surface;)I",
+ (void*) nativeSetSurface },
+ { "nativeGetStreamConfigs", "(JII)[Landroid/tv/TvStreamConfig;",
+ (void*) nativeGetStreamConfigs },
+ { "nativeClose", "(J)V",
+ (void*) nativeClose },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className)
+
+#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method" methodName)
+
+int register_android_server_tv_TvInputHal(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal",
+ gTvInputHalMethods, NELEM(gTvInputHalMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/tv/TvInputHal");
+
+ GET_METHOD_ID(
+ gTvInputHalClassInfo.deviceAvailable, clazz, "deviceAvailableFromNative", "(II)V");
+ GET_METHOD_ID(
+ gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
+ GET_METHOD_ID(
+ gTvInputHalClassInfo.streamConfigsChanged, clazz,
+ "streamConfigsChangedFromNative", "(I)V");
+
+ FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/tv/TvStreamConfig");
+ gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz));
+
+ FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/tv/TvStreamConfig$Builder");
+ gTvStreamConfigBuilderClassInfo.clazz =
+ jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz));
+
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.constructor,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "<init>", "()V");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.streamId,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "streamId", "(I)Landroid/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.type,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "type", "(I)Landroid/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.maxWidth,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "maxWidth", "(I)Landroid/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.maxHeight,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "maxHeight", "(I)Landroid/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.generation,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "generation", "(I)Landroid/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.build,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "build", "()Landroid/tv/TvStreamConfig;");
+
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1feb325..bfa8286 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,7 @@ int register_android_server_dreams_McuHal(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
+int register_android_server_tv_TvInputHal(JNIEnv* env);
};
using namespace android;
@@ -78,6 +79,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
// TODO: remove this once replaces HdmiCecService with HdmiControlService.
register_android_server_hdmi_HdmiCecService(env);
register_android_server_hdmi_HdmiMhlController(env);
+ register_android_server_tv_TvInputHal(env);
return JNI_VERSION_1_4;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de46b16..0f24ff6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@ import com.android.server.power.ShutdownThread;
import com.android.server.search.SearchManagerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.task.TaskManagerService;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.twilight.TwilightService;
@@ -132,6 +133,8 @@ public final class SystemServer {
"com.android.server.hdmi.HdmiCecService";
private static final String ETHERNET_SERVICE_CLASS =
"com.android.server.ethernet.EthernetService";
+ private static final String TASK_SERVICE_CLASS =
+ "com.android.server.task.TaskManagerService";
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -183,7 +186,7 @@ public final class SystemServer {
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
- SystemProperties.set("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary());
+ SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
@@ -831,6 +834,8 @@ public final class SystemServer {
mSystemServiceManager.startService(UiModeManagerService.class);
+ mSystemServiceManager.startService(TaskManagerService.class);
+
if (!disableNonCoreServices) {
try {
if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 9b6daad..62ff121 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -113,7 +113,7 @@ class VoiceInteractionManagerServiceImpl {
if (mBound) {
try {
mIWindowManager.addWindowToken(mToken,
- WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+ WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
} catch (RemoteException e) {
Slog.w(TAG, "Failed adding window token", e);
}