Merge "Do not get device owner admin info when device owner is null" into nyc-dev
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 03f83d6..4bbbdee 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -459,23 +459,19 @@
/**
* Ask the package manager to perform dex-opt (if needed) on the given
- * package and for the given instruction set if it already hasn't done
- * so.
- *
- * If the supplied instructionSet is null, the package manager will use
- * the packages default instruction set.
+ * package if it already hasn't done so.
*
* In most cases, apps are dexopted in advance and this function will
* be a no-op.
*/
- boolean performDexOptIfNeeded(String packageName, String instructionSet);
+ boolean performDexOptIfNeeded(String packageName);
/**
* Ask the package manager to perform a dex-opt for the given reason. The package
* manager will map the reason to a compiler filter according to the current system
* configuration.
*/
- boolean performDexOpt(String packageName, String instructionSet, boolean checkProfiles,
+ boolean performDexOpt(String packageName, boolean checkProfiles,
int compileReason, boolean force);
/**
* Ask the package manager to perform a dex-opt with the given compiler filter.
@@ -483,7 +479,7 @@
* Note: exposed only for the shell command to allow moving packages explicitly to a
* definite state.
*/
- boolean performDexOptMode(String packageName, String instructionSet, boolean checkProfiles,
+ boolean performDexOptMode(String packageName, boolean checkProfiles,
String targetCompilerFilter, boolean force);
void forceDexOpt(String packageName);
diff --git a/docs/html/images/training/tv/playback/guided-step-buttonaction-2x.png b/docs/html/images/training/tv/playback/guided-step-buttonaction-2x.png
new file mode 100644
index 0000000..059cf0a
--- /dev/null
+++ b/docs/html/images/training/tv/playback/guided-step-buttonaction-2x.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/guided-step-buttonaction.png b/docs/html/images/training/tv/playback/guided-step-buttonaction.png
new file mode 100644
index 0000000..aacb844
--- /dev/null
+++ b/docs/html/images/training/tv/playback/guided-step-buttonaction.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/guided-step-subaction-2x.png b/docs/html/images/training/tv/playback/guided-step-subaction-2x.png
new file mode 100644
index 0000000..411bee4
--- /dev/null
+++ b/docs/html/images/training/tv/playback/guided-step-subaction-2x.png
Binary files differ
diff --git a/docs/html/images/training/tv/playback/guided-step-subaction.png b/docs/html/images/training/tv/playback/guided-step-subaction.png
new file mode 100644
index 0000000..5b004d5
--- /dev/null
+++ b/docs/html/images/training/tv/playback/guided-step-subaction.png
Binary files differ
diff --git a/docs/html/training/tv/playback/guided-step.jd b/docs/html/training/tv/playback/guided-step.jd
index 121961f..99e5c08 100644
--- a/docs/html/training/tv/playback/guided-step.jd
+++ b/docs/html/training/tv/playback/guided-step.jd
@@ -1,5 +1,6 @@
page.title=Adding a Guided Step
-page.tags=tv, guided step
+page.tags=tv,guided step,GuidedStepFragment,GuidedAction
+page.keywords=tv,GuidedStepFragment,GuidedAction
helpoutsWidget=true
trainingnavtop=true
@@ -12,7 +13,7 @@
<ol>
<li><a href="#details">Provide Details for a Step</a></li>
<li><a href="#actions">Create and Handle User Actions</a></li>
- <li><a href="#sequence">Group Guided Steps Into a Sequence</a></li>
+ <li><a href="#sequence">Group Guided Steps Into a Guided Sequence</a></li>
<li><a href="#presentation">Customize Step Presentation</a></li>
</ol>
<h2>Try it out</h2>
@@ -107,7 +108,7 @@
<pre>
@Override
-public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
// Add "Continue" user action for this step
actions.add(new GuidedAction.Builder()
.id(CONTINUE)
@@ -119,39 +120,60 @@
</pre>
<p>
-Actions aren’t limited to single-line selections. Use
-{@link android.support.v17.leanback.widget.GuidedAction} attributes
-to add the following additional types of actions:
+Actions aren't limited to single-line selections. Here are additional types of
+actions you can create:
</p>
<ul>
<li>
-Add a information label action by setting
+Add an information label action by setting
{@link android.support.v17.leanback.widget.GuidedAction.Builder#infoOnly infoOnly(true)}.
-If <code>infoOnly</code> is set to true, the action can't be selected by the user. Use label
-actions to provide additional information about user choices.
+If you set <code>infoOnly</code> to true, the user can't select the action. To
+provide additional information about user choices, use label actions.
</li>
<li>
Add an editable text action by setting
{@link android.support.v17.leanback.widget.GuidedAction.Builder#editable editable(true)}. If
<code>editable</code> is true, when the action is selected the user can enter text using the
-remote or a connected keyboard.
+remote or a connected keyboard. Override
+{@link android.support.v17.leanback.app.GuidedStepFragment#onGuidedActionEdited
+onGuidedActionEdited()} or
+{@code onGuidedActionEditedAndProceed()} to get the modified text the user entered.
</li>
<li>
Add a set of actions that behave as checkable radio buttons by using
{@link android.support.v17.leanback.widget.GuidedAction.Builder#checkSetId checkSetId()}
with a common ID value to group actions into a set. All actions in the same list with the same
-check-set ID are considered linked. When one of the actions within that set is selected, that
+check-set ID are considered linked. When the user selects one of the actions within that set, that
action becomes checked, while all other actions become unchecked.
</li>
+<li>
+Add a date-picker action by using
+{@code GuidedDatePickerAction.Builder}
+instead of
+{@link android.support.v17.leanback.widget.GuidedAction.Builder} in
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateActions
+onCreateActions()}. Override
+{@link android.support.v17.leanback.app.GuidedStepFragment#onGuidedActionEdited
+onGuidedActionEdited()} or
+{@code onGuidedActionEditedAndProceed()} to get the modified date value the user entered.
+</li>
+<li>
+Add an action that uses subactions to let the user pick from an extended list of
+choices. Subactions are described in <a href="#subactions">Add subactions</a>.
+</li>
+<li>
+Add a button action that appears to the right of the actions list and is easily
+accessible. Button actions are described in <a href="#buttonactions">Add button
+actions</a>.</li>
</ul>
<p>
-You can also add a visual indicator that indicates selecting the action leads to a new step by
-setting
+You can also add a visual indicator—to indicate that selecting the action
+leads to a new step—by setting
{@link android.support.v17.leanback.widget.GuidedAction#hasNext hasNext(true)}.
-See {@link android.support.v17.leanback.widget.GuidedAction} for all the different attributes
-you can set.
+For all the different attributes that you can set, see
+{@link android.support.v17.leanback.widget.GuidedAction}.
</p>
<p>
@@ -162,6 +184,111 @@
examining {@link android.support.v17.leanback.widget.GuidedAction#getId GuidedAction.getId()}.
</p>
+<h3 id="subactions">Add subactions</h3>
+
+<p>
+Some actions might require giving the user an additional set of choices. A
+{@link android.support.v17.leanback.widget.GuidedAction} can specify a list of
+subactions that get displayed as a drop-down list of child actions.
+</p>
+
+<img src="{@docRoot}images/training/tv/playback/guided-step-subaction.png"
+srcset="{@docRoot}images/training/tv/playback/guided-step-subaction.png 1x,
+{@docRoot}images/training/tv/playback/guided-step-subaction-2x.png 2x" />
+<p class="img-caption"><strong>Figure 2.</strong> Guided step subactions.</p>
+
+<p>
+The subaction list can contain regular actions or radio button actions, but
+not date-picker or editable text actions. Also, a subaction cannot have its own
+set of subactions as the system does not support more than one level of subactions.
+Deeply nested sets of actions create a poor user experience.
+</p>
+
+<p>
+To add subactions, first create and populate a list of
+{@link android.support.v17.leanback.widget.GuidedAction GuidedActions} that will
+act as subactions:
+</p>
+
+<pre>
+List<GuidedAction> subActions = new ArrayList<GuidedAction>();
+subActions.add(new GuidedAction.Builder()
+ .id(SUBACTION1)
+ .title(getString(R.string.guidedstep_subaction1_title))
+ .description(getString(R.string.guidedstep_subaction1_desc))
+ .build());
+...
+</pre>
+
+<p>
+In {@link android.support.v17.leanback.app.GuidedStepFragment#onCreateActions
+onCreateActions()}, create a top-level
+{@link android.support.v17.leanback.widget.GuidedAction} that will display the
+list of subactions when selected:
+</p>
+
+<pre>
+@Override
+public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+...
+ actions.add(new GuidedAction.Builder()
+ .id(SUBACTIONS)
+ .title(getString(R.string.guidedstep_subactions_title))
+ .description(getString(R.string.guidedstep_subactions_desc))
+ <b>.subActions(subActions)</b>
+ .build());
+...
+}
+</pre>
+
+<p>
+Finally, respond to subaction selections by overriding
+{@code onSubGuidedActionClicked()}:
+</p>
+
+<pre>
+@Override
+public boolean onSubGuidedActionClicked(GuidedAction action) {
+ // Check for which action was clicked, and handle as needed
+ if (action.getId() == SUBACTION1) {
+ // Subaction 1 selected
+ }
+ // Return true to collapse the subactions drop-down list, or
+ // false to keep the drop-down list expanded.
+ return true;
+}
+</pre>
+
+<h3 id="buttonactions">Add button actions</h3>
+
+<p>
+If your guided step has a large list of actions, users may have to scroll through the list
+to access the most commonly used actions. Use button actions to separate
+commonly used actions from the action list. Button actions appear to the right
+of the action list and are easy to navigate to.
+</p>
+
+<img src="{@docRoot}images/training/tv/playback/guided-step-buttonaction.png"
+srcset="{@docRoot}images/training/tv/playback/guided-step-buttonaction.png 1x,
+{@docRoot}images/training/tv/playback/guided-step-buttonaction-2x.png 2x" />
+<p class="img-caption"><strong>Figure 3.</strong> Guided step button actions.</p>
+
+<p>
+Button actions are created and handled just like regular actions, but you create
+button actions in
+{@code onCreateButtonActions()} instead of
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateActions
+onCreateActions()}. Respond to button actions in
+{@link android.support.v17.leanback.app.GuidedStepFragment#onGuidedActionClicked
+onGuidedActionClicked()}.
+</p>
+
+<p>
+Use button actions for simple actions, such as navigation actions between steps.
+Don't use the date-picker action or other editable actions as button actions.
+Also, button actions cannot have subactions.
+</p>
+
<h2 id="sequence">Group Guided Steps Into a Guided Sequence</h2>
<p>
@@ -188,6 +315,20 @@
decide to provide your own {@link android.support.v17.leanback.widget.GuidedAction} that
returns to the previous step, you can implement the Back behavior by calling
{@link android.app.FragmentManager#popBackStack getFragmentManager().popBackStack()}.
+If you need to return the user to an even earlier step in the sequence, use
+{@code popBackStackToGuidedStepFragment()} to return to a specific
+{@link android.support.v17.leanback.app.GuidedStepFragment} in the fragment stack.
+</p>
+
+<p>
+When the user has finished the last step in the sequence, use
+{@code finishGuidedStepFragments()} to remove all
+{@link android.support.v17.leanback.app.GuidedStepFragment GuidedStepFragments}
+from the current stack and return to the original parent activity. If the
+first {@link android.support.v17.leanback.app.GuidedStepFragment} was added
+using {@link android.support.v17.leanback.app.GuidedStepFragment#addAsRoot
+addAsRoot()}, calling
+{@code finishGuidedStepFragments()} will also close the parent activity.
</p>
<h2 id="presentation">Customize Step Presentation</h2>
@@ -220,11 +361,11 @@
{@link android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme}
attribute to your existing custom activity theme. This attribute points to the custom theme that
only the {@link android.support.v17.leanback.app.GuidedStepFragment} objects in your
-activity will use.
+activity use.
</li>
<li>
If you use {@link android.support.v17.leanback.app.GuidedStepFragment} objects in different
-activities that are part of the same overall multi-step task, and want to use a consistent
+activities that are part of the same overall multi-step task and want to use a consistent
visual theme across all steps, override
{@link android.support.v17.leanback.app.GuidedStepFragment#onProvideTheme
GuidedStepFragment.onProvideTheme()} and return your custom theme.
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index ee02a99..87f0581 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -154,7 +154,6 @@
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
pm.performDexOpt(pkg,
- /* instruction set */ null,
/* checkProfiles */ false,
PackageManagerService.REASON_BOOT,
/* force */ false);
@@ -192,7 +191,6 @@
// Optimize package if needed. Note that there can be no race between
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
if (pm.performDexOpt(pkg,
- /* instruction set */ null,
/* checkProfiles */ true,
PackageManagerService.REASON_BACKGROUND_DEXOPT,
/* force */ false)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 08b9c78..a2bdde4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7267,7 +7267,6 @@
// behave differently than "pm.dexopt.bg-dexopt=speed-profile" but that's a
// trade-off worth doing to save boot time work.
int dexOptStatus = performDexOptTraced(pkg.packageName,
- null /* instructionSet */,
false /* checkProfiles */,
getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
false /* force */);
@@ -7309,33 +7308,33 @@
// TODO: this is not used nor needed. Delete it.
@Override
- public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
- int dexOptStatus = performDexOptTraced(packageName, instructionSet,
+ public boolean performDexOptIfNeeded(String packageName) {
+ int dexOptStatus = performDexOptTraced(packageName,
false /* checkProfiles */, getFullCompilerFilter(), false /* force */);
return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
@Override
- public boolean performDexOpt(String packageName, String instructionSet,
+ public boolean performDexOpt(String packageName,
boolean checkProfiles, int compileReason, boolean force) {
- int dexOptStatus = performDexOptTraced(packageName, instructionSet, checkProfiles,
+ int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
getCompilerFilterForReason(compileReason), force);
return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
@Override
- public boolean performDexOptMode(String packageName, String instructionSet,
+ public boolean performDexOptMode(String packageName,
boolean checkProfiles, String targetCompilerFilter, boolean force) {
- int dexOptStatus = performDexOptTraced(packageName, instructionSet, checkProfiles,
+ int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
targetCompilerFilter, force);
return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
}
- private int performDexOptTraced(String packageName, String instructionSet,
+ private int performDexOptTraced(String packageName,
boolean checkProfiles, String targetCompilerFilter, boolean force) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
try {
- return performDexOptInternal(packageName, instructionSet, checkProfiles,
+ return performDexOptInternal(packageName, checkProfiles,
targetCompilerFilter, force);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -7344,10 +7343,9 @@
// Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
// if the package can now be considered up to date for the given filter.
- private int performDexOptInternal(String packageName, String instructionSet,
+ private int performDexOptInternal(String packageName,
boolean checkProfiles, String targetCompilerFilter, boolean force) {
PackageParser.Package p;
- final String targetInstructionSet;
synchronized (mPackages) {
p = mPackages.get(packageName);
if (p == null) {
@@ -7355,15 +7353,11 @@
return PackageDexOptimizer.DEX_OPT_FAILED;
}
mPackageUsage.write(false);
-
- targetInstructionSet = instructionSet != null ? instructionSet :
- getPrimaryInstructionSet(p.applicationInfo);
}
long callingId = Binder.clearCallingIdentity();
try {
synchronized (mInstallLock) {
- final String[] instructionSets = new String[] { targetInstructionSet };
- return performDexOptInternalWithDependenciesLI(p, instructionSets, checkProfiles,
+ return performDexOptInternalWithDependenciesLI(p, checkProfiles,
targetCompilerFilter, force);
}
} finally {
@@ -7384,7 +7378,7 @@
}
private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
- String instructionSets[], boolean checkProfiles, String targetCompilerFilter,
+ boolean checkProfiles, String targetCompilerFilter,
boolean force) {
// Select the dex optimizer based on the force parameter.
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
@@ -7396,6 +7390,7 @@
// Optimize all dependencies first. Note: we ignore the return value and march on
// on errors.
Collection<PackageParser.Package> deps = findSharedNonSystemLibraries(p);
+ final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
if (!deps.isEmpty()) {
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
@@ -7405,7 +7400,6 @@
getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY));
}
}
-
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
targetCompilerFilter);
}
@@ -7477,14 +7471,11 @@
}
synchronized (mInstallLock) {
- final String[] instructionSets = new String[] {
- getPrimaryInstructionSet(pkg.applicationInfo) };
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
// Whoever is calling forceDexOpt wants a fully compiled package.
// Don't use profiles since that may cause compilation to be skipped.
- final int res = performDexOptInternalWithDependenciesLI(pkg, instructionSets,
+ final int res = performDexOptInternalWithDependenciesLI(pkg,
false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
true /* force */);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index b305ba7..751c585 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,6 +34,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
@@ -66,15 +68,15 @@
}
private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
+ long estimatedPreviousSystemUseTime,
long dexOptLRUThresholdInMills) {
// Filter out packages that aren't recently used.
int total = pkgs.size();
int skipped = 0;
- long now = System.currentTimeMillis();
for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
PackageParser.Package pkg = i.next();
long then = pkg.getLatestForegroundPackageUseTimeInMills();
- if (then + dexOptLRUThresholdInMills < now) {
+ if (then < estimatedPreviousSystemUseTime - dexOptLRUThresholdInMills) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Skipping dexopt of " + pkg.packageName +
" last used in foreground: " +
@@ -82,6 +84,12 @@
}
i.remove();
skipped++;
+ } else {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Will dexopt " + pkg.packageName +
+ " last used in foreground: " +
+ ((then == 0) ? "never" : new Date(then)));
+ }
}
}
if (DEBUG_DEXOPT) {
@@ -136,8 +144,24 @@
// Filter out packages that aren't recently used, add all remaining apps.
// TODO: add a property to control this?
- if (packageManagerService.isHistoricalPackageUsageAvailable()) {
- filterRecentlyUsedApps(remainingPkgs, SEVEN_DAYS_IN_MILLISECONDS);
+ if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Looking at historical package use");
+ }
+ // Get the package that was used last.
+ PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
+ Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
+ pkg2.getLatestForegroundPackageUseTimeInMills()));
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
+ }
+ long estimatedPreviousSystemUseTime =
+ lastUsed.getLatestForegroundPackageUseTimeInMills();
+ // Be defensive if for some reason package usage has bogus data.
+ if (estimatedPreviousSystemUseTime != 0) {
+ filterRecentlyUsedApps(remainingPkgs, estimatedPreviousSystemUseTime,
+ SEVEN_DAYS_IN_MILLISECONDS);
+ }
}
result.addAll(remainingPkgs);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1eeff14..beff8fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -358,7 +358,7 @@
mInterface.clearApplicationProfileData(packageName);
}
- boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */,
+ boolean result = mInterface.performDexOptMode(packageName,
checkProfiles, targetCompilerFilter, forceCompilation);
if (!result) {
failedPackages.add(packageName);