summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt14
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java332
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java9
-rw-r--r--core/java/android/provider/Settings.java3
-rw-r--r--core/java/android/view/View.java134
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java168
-rw-r--r--core/java/android/widget/RemoteViews.java20
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java4
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java80
-rw-r--r--core/jni/android/graphics/pdf/PdfEditor.cpp204
-rw-r--r--core/res/res/values/attrs.xml12
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java155
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl2
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java109
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java38
16 files changed, 1073 insertions, 213 deletions
diff --git a/api/current.txt b/api/current.txt
index 3fdb1a3..4445e3f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -239,6 +239,8 @@ package android {
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
field public static final int accessibilityFlags = 16843652; // 0x1010384
field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
+ field public static final int accessibilityTraversalAfter = 16844036; // 0x1010504
+ field public static final int accessibilityTraversalBefore = 16844035; // 0x1010503
field public static final int accountPreferences = 16843423; // 0x101029f
field public static final int accountType = 16843407; // 0x101028f
field public static final int action = 16842797; // 0x101002d
@@ -33611,6 +33613,8 @@ package android.view {
method public static int generateViewId();
method public int getAccessibilityLiveRegion();
method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
+ method public int getAccessibilityTraversalAfter();
+ method public int getAccessibilityTraversalBefore();
method public float getAlpha();
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
@@ -33887,6 +33891,8 @@ package android.view {
method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
method public void setAccessibilityLiveRegion(int);
+ method public void setAccessibilityTraversalAfter(int);
+ method public void setAccessibilityTraversalBefore(int);
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
@@ -35166,6 +35172,8 @@ package android.view.accessibility {
method public java.lang.CharSequence getText();
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
+ method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
+ method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
method public java.lang.String getViewIdResourceName();
method public android.view.accessibility.AccessibilityWindowInfo getWindow();
method public int getWindowId();
@@ -35236,6 +35244,10 @@ package android.view.accessibility {
method public void setSource(android.view.View, int);
method public void setText(java.lang.CharSequence);
method public void setTextSelection(int, int);
+ method public void setTraversalAfter(android.view.View);
+ method public void setTraversalAfter(android.view.View, int);
+ method public void setTraversalBefore(android.view.View);
+ method public void setTraversalBefore(android.view.View, int);
method public void setViewIdResourceName(java.lang.String);
method public void setVisibleToUser(boolean);
method public void writeToParcel(android.os.Parcel, int);
@@ -38433,6 +38445,8 @@ package android.widget {
method public boolean onLoadClass(java.lang.Class);
method public void reapply(android.content.Context, android.view.View);
method public void removeAllViews(int);
+ method public void setAccessibilityTraversalAfter(int, int);
+ method public void setAccessibilityTraversalBefore(int, int);
method public void setBitmap(int, java.lang.String, android.graphics.Bitmap);
method public void setBoolean(int, java.lang.String, boolean);
method public void setBundle(int, java.lang.String, android.os.Bundle);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 5e9d8f7..7fd586f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -96,8 +96,9 @@ public final class Pm {
"Error: Could not access the Package Manager. Is the system running?";
public static void main(String[] args) {
+ int exitCode = 1;
try {
- new Pm().run(args);
+ exitCode = new Pm().run(args);
} catch (Exception e) {
Log.e(TAG, "Error", e);
System.err.println("Error: " + e);
@@ -105,20 +106,20 @@ public final class Pm {
System.err.println(PM_NOT_RUNNING_ERR);
}
}
+ System.exit(exitCode);
}
- public void run(String[] args) throws IOException, RemoteException {
+ public int run(String[] args) throws IOException, RemoteException {
boolean validCommand = false;
if (args.length < 1) {
- showUsage();
- return;
+ return showUsage();
}
mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
System.err.println(PM_NOT_RUNNING_ERR);
- return;
+ return 1;
}
mInstaller = mPm.getPackageInstaller();
@@ -127,155 +128,129 @@ public final class Pm {
mNextArg = 1;
if ("list".equals(op)) {
- runList();
- return;
+ return runList();
}
if ("path".equals(op)) {
- runPath();
- return;
+ return runPath();
}
if ("dump".equals(op)) {
- runDump();
- return;
+ return runDump();
}
if ("install".equals(op)) {
- runInstall();
- return;
+ return runInstall();
}
if ("install-create".equals(op)) {
- runInstallCreate();
- return;
+ return runInstallCreate();
}
if ("install-write".equals(op)) {
- runInstallWrite();
- return;
+ return runInstallWrite();
}
if ("install-commit".equals(op)) {
- runInstallCommit();
- return;
+ return runInstallCommit();
}
if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
- runInstallAbandon();
- return;
+ return runInstallAbandon();
}
if ("set-installer".equals(op)) {
- runSetInstaller();
- return;
+ return runSetInstaller();
}
if ("uninstall".equals(op)) {
- runUninstall();
- return;
+ return runUninstall();
}
if ("clear".equals(op)) {
- runClear();
- return;
+ return runClear();
}
if ("enable".equals(op)) {
- runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
- return;
+ return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
if ("disable".equals(op)) {
- runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
- return;
+ return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
}
if ("disable-user".equals(op)) {
- runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
- return;
+ return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
}
if ("disable-until-used".equals(op)) {
- runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
- return;
+ return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
}
if ("hide".equals(op)) {
- runSetHiddenSetting(true);
- return;
+ return runSetHiddenSetting(true);
}
if ("unhide".equals(op)) {
- runSetHiddenSetting(false);
- return;
+ return runSetHiddenSetting(false);
}
if ("grant".equals(op)) {
- runGrantRevokePermission(true);
- return;
+ return runGrantRevokePermission(true);
}
if ("revoke".equals(op)) {
- runGrantRevokePermission(false);
- return;
+ return runGrantRevokePermission(false);
}
if ("set-permission-enforced".equals(op)) {
- runSetPermissionEnforced();
- return;
+ return runSetPermissionEnforced();
}
if ("set-install-location".equals(op)) {
- runSetInstallLocation();
- return;
+ return runSetInstallLocation();
}
if ("get-install-location".equals(op)) {
- runGetInstallLocation();
- return;
+ return runGetInstallLocation();
}
if ("trim-caches".equals(op)) {
- runTrimCaches();
- return;
+ return runTrimCaches();
}
if ("create-user".equals(op)) {
- runCreateUser();
- return;
+ return runCreateUser();
}
if ("remove-user".equals(op)) {
- runRemoveUser();
- return;
+ return runRemoveUser();
}
if ("get-max-users".equals(op)) {
- runGetMaxUsers();
- return;
+ return runGetMaxUsers();
}
if ("force-dex-opt".equals(op)) {
- runForceDexOpt();
- return;
+ return runForceDexOpt();
}
try {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("-l")) {
validCommand = true;
- runListPackages(false);
+ return runListPackages(false);
} else if (args[0].equalsIgnoreCase("-lf")){
validCommand = true;
- runListPackages(true);
+ return runListPackages(true);
}
} else if (args.length == 2) {
if (args[0].equalsIgnoreCase("-p")) {
validCommand = true;
- displayPackageFilePath(args[1]);
+ return displayPackageFilePath(args[1]);
}
}
+ return 1;
} finally {
if (validCommand == false) {
if (op != null) {
@@ -296,35 +271,36 @@ public final class Pm {
* pm list libraries
* pm list instrumentation
*/
- private void runList() {
+ private int runList() {
String type = nextArg();
if (type == null) {
System.err.println("Error: didn't specify type of data to list");
- return;
+ return 1;
}
if ("package".equals(type) || "packages".equals(type)) {
- runListPackages(false);
+ return runListPackages(false);
} else if ("permission-groups".equals(type)) {
- runListPermissionGroups();
+ return runListPermissionGroups();
} else if ("permissions".equals(type)) {
- runListPermissions();
+ return runListPermissions();
} else if ("features".equals(type)) {
- runListFeatures();
+ return runListFeatures();
} else if ("libraries".equals(type)) {
- runListLibraries();
+ return runListLibraries();
} else if ("instrumentation".equals(type)) {
- runListInstrumentation();
+ return runListInstrumentation();
} else if ("users".equals(type)) {
- runListUsers();
+ return runListUsers();
} else {
System.err.println("Error: unknown list type '" + type + "'");
+ return 1;
}
}
/**
* Lists all the installed packages.
*/
- private void runListPackages(boolean showApplicationPackage) {
+ private int runListPackages(boolean showApplicationPackage) {
int getFlags = 0;
boolean listDisabled = false, listEnabled = false;
boolean listSystem = false, listThirdParty = false;
@@ -355,12 +331,12 @@ public final class Pm {
getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
} else {
System.err.println("Error: Unknown option: " + opt);
- return;
+ return 1;
}
}
} catch (RuntimeException ex) {
System.err.println("Error: " + ex.toString());
- return;
+ return 1;
}
String filter = nextArg();
@@ -393,9 +369,11 @@ public final class Pm {
System.out.println();
}
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -411,7 +389,7 @@ public final class Pm {
*
* pm list features
*/
- private void runListFeatures() {
+ private int runListFeatures() {
try {
List<FeatureInfo> list = new ArrayList<FeatureInfo>();
FeatureInfo[] rawList = mPm.getSystemAvailableFeatures();
@@ -438,9 +416,11 @@ public final class Pm {
else System.out.println("reqGlEsVersion=0x"
+ Integer.toHexString(fi.reqGlEsVersion));
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -449,7 +429,7 @@ public final class Pm {
*
* pm list libraries
*/
- private void runListLibraries() {
+ private int runListLibraries() {
try {
List<String> list = new ArrayList<String>();
String[] rawList = mPm.getSystemSharedLibraryNames();
@@ -474,9 +454,11 @@ public final class Pm {
System.out.print("library:");
System.out.println(lib);
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -485,7 +467,7 @@ public final class Pm {
*
* pm list instrumentation [package] [-f]
*/
- private void runListInstrumentation() {
+ private int runListInstrumentation() {
int flags = 0; // flags != 0 is only used to request meta-data
boolean showPackage = false;
String targetPackage = null;
@@ -499,12 +481,12 @@ public final class Pm {
targetPackage = opt;
} else {
System.err.println("Error: Unknown option: " + opt);
- return;
+ return 1;
}
}
} catch (RuntimeException ex) {
System.err.println("Error: " + ex.toString());
- return;
+ return 1;
}
try {
@@ -531,16 +513,18 @@ public final class Pm {
System.out.print(ii.targetPackage);
System.out.println(")");
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
/**
* Lists all the known permission groups.
*/
- private void runListPermissionGroups() {
+ private int runListPermissionGroups() {
try {
List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0);
@@ -550,9 +534,11 @@ public final class Pm {
System.out.print("permission group:");
System.out.println(pgi.name);
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -572,7 +558,7 @@ public final class Pm {
/**
* Lists all the permissions in a group.
*/
- private void runListPermissions() {
+ private int runListPermissions() {
try {
boolean labels = false;
boolean groups = false;
@@ -595,7 +581,7 @@ public final class Pm {
dangerousOnly = true;
} else {
System.err.println("Error: Unknown option: " + opt);
- return;
+ return 1;
}
}
@@ -637,9 +623,11 @@ public final class Pm {
doListPermissions(groupList, groups, labels, summary,
-10000, 10000);
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -739,22 +727,23 @@ public final class Pm {
}
}
- private void runPath() {
+ private int runPath() {
String pkg = nextArg();
if (pkg == null) {
System.err.println("Error: no package specified");
- return;
+ return 1;
}
- displayPackageFilePath(pkg);
+ return displayPackageFilePath(pkg);
}
- private void runDump() {
+ private int runDump() {
String pkg = nextArg();
if (pkg == null) {
System.err.println("Error: no package specified");
- return;
+ return 1;
}
ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
+ return 0;
}
class LocalPackageInstallObserver extends PackageInstallObserver {
@@ -822,31 +811,34 @@ public final class Pm {
return Integer.toString(result);
}
- private void runSetInstallLocation() {
+ private int runSetInstallLocation() {
int loc;
String arg = nextArg();
if (arg == null) {
System.err.println("Error: no install location specified.");
- return;
+ return 1;
}
try {
loc = Integer.parseInt(arg);
} catch (NumberFormatException e) {
System.err.println("Error: install location has to be a number.");
- return;
+ return 1;
}
try {
if (!mPm.setInstallLocation(loc)) {
System.err.println("Error: install location has to be a number.");
+ return 1;
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- private void runGetInstallLocation() {
+ private int runGetInstallLocation() {
try {
int loc = mPm.getInstallLocation();
String locStr = "invalid";
@@ -858,13 +850,15 @@ public final class Pm {
locStr = "external";
}
System.out.println(loc + "[" + locStr + "]");
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- private void runInstall() {
+ private int runInstall() {
int installFlags = 0;
int userId = UserHandle.USER_ALL;
String installerPackageName = null;
@@ -884,7 +878,7 @@ public final class Pm {
installerPackageName = nextOptionData();
if (installerPackageName == null) {
System.err.println("Error: no value specified for -i");
- return;
+ return 1;
}
} else if (opt.equals("-t")) {
installFlags |= PackageManager.INSTALL_ALLOW_TEST;
@@ -900,13 +894,13 @@ public final class Pm {
originatingUriString = nextOptionData();
if (originatingUriString == null) {
System.err.println("Error: must supply argument for --originating-uri");
- return;
+ return 1;
}
} else if (opt.equals("--referrer")) {
referrer = nextOptionData();
if (referrer == null) {
System.err.println("Error: must supply argument for --referrer");
- return;
+ return 1;
}
} else if (opt.equals("--abi")) {
abi = checkAbiArgument(nextOptionData());
@@ -914,7 +908,7 @@ public final class Pm {
userId = Integer.parseInt(nextOptionData());
} else {
System.err.println("Error: Unknown option: " + opt);
- return;
+ return 1;
}
}
@@ -944,7 +938,7 @@ public final class Pm {
System.err.println("\tpkg: " + apkFilePath);
if (apkFilePath == null) {
System.err.println("Error: no package specified");
- return;
+ return 1;
}
// Populate verificationURI, optionally present
@@ -973,19 +967,22 @@ public final class Pm {
}
if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
System.out.println("Success");
+ return 0;
} else {
System.err.println("Failure ["
+ installFailureToString(obs)
+ "]");
+ return 1;
}
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- private void runInstallCreate() throws RemoteException {
+ private int runInstallCreate() throws RemoteException {
int userId = UserHandle.USER_ALL;
String installerPackageName = null;
@@ -1040,9 +1037,10 @@ public final class Pm {
// NOTE: adb depends on parsing this string
System.out.println("Success: created install session [" + sessionId + "]");
+ return 0;
}
- private void runInstallWrite() throws IOException, RemoteException {
+ private int runInstallWrite() throws IOException, RemoteException {
long sizeBytes = -1;
String opt;
@@ -1097,6 +1095,7 @@ public final class Pm {
session.fsync(out);
System.out.println("Success: streamed " + total + " bytes");
+ return 0;
} finally {
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
@@ -1104,7 +1103,7 @@ public final class Pm {
}
}
- private void runInstallCommit() throws RemoteException {
+ private int runInstallCommit() throws RemoteException {
final int sessionId = Integer.parseInt(nextArg());
PackageInstaller.Session session = null;
@@ -1119,18 +1118,19 @@ public final class Pm {
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
System.out.println("Success");
+ return 0;
} else {
Log.e(TAG, "Failure details: " + result.getExtras());
- System.out.println("Failure ["
+ System.err.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
- return;
+ return 1;
}
} finally {
IoUtils.closeQuietly(session);
}
}
- private void runInstallAbandon() throws RemoteException {
+ private int runInstallAbandon() throws RemoteException {
final int sessionId = Integer.parseInt(nextArg());
PackageInstaller.Session session = null;
@@ -1138,12 +1138,13 @@ public final class Pm {
session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
session.abandon();
System.out.println("Success");
+ return 0;
} finally {
IoUtils.closeQuietly(session);
}
}
- private void runSetInstaller() throws RemoteException {
+ private int runSetInstaller() throws RemoteException {
final String targetPackage = nextArg();
final String installerPackageName = nextArg();
@@ -1154,9 +1155,10 @@ public final class Pm {
mPm.setInstallerPackageName(targetPackage, installerPackageName);
System.out.println("Success");
+ return 0;
}
- public void runCreateUser() {
+ public int runCreateUser() {
String name;
int userId = -1;
int flags = 0;
@@ -1167,7 +1169,7 @@ public final class Pm {
if (optionData == null || !isNumber(optionData)) {
System.err.println("Error: no USER_ID specified");
showUsage();
- return;
+ return 1;
} else {
userId = Integer.parseInt(optionData);
}
@@ -1176,13 +1178,13 @@ public final class Pm {
} else {
System.err.println("Error: unknown option " + opt);
showUsage();
- return;
+ return 1;
}
}
String arg = nextArg();
if (arg == null) {
System.err.println("Error: no user name specified.");
- return;
+ return 1;
}
name = arg;
try {
@@ -1194,75 +1196,85 @@ public final class Pm {
}
if (info != null) {
System.out.println("Success: created user id " + info.id);
+ return 1;
} else {
System.err.println("Error: couldn't create User.");
+ return 1;
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
-
}
- public void runRemoveUser() {
+ public int runRemoveUser() {
int userId;
String arg = nextArg();
if (arg == null) {
System.err.println("Error: no user id specified.");
- return;
+ return 1;
}
try {
userId = Integer.parseInt(arg);
} catch (NumberFormatException e) {
System.err.println("Error: user id '" + arg + "' is not a number.");
- return;
+ return 1;
}
try {
if (mUm.removeUser(userId)) {
System.out.println("Success: removed user");
+ return 0;
} else {
System.err.println("Error: couldn't remove user id " + userId);
+ return 1;
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- public void runListUsers() {
+ public int runListUsers() {
try {
IActivityManager am = ActivityManagerNative.getDefault();
List<UserInfo> users = mUm.getUsers(false);
if (users == null) {
System.err.println("Error: couldn't get users");
+ return 1;
} else {
System.out.println("Users:");
for (int i = 0; i < users.size(); i++) {
String running = am.isUserRunning(users.get(i).id, false) ? " running" : "";
System.out.println("\t" + users.get(i).toString() + running);
}
+ return 0;
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- public void runGetMaxUsers() {
+ public int runGetMaxUsers() {
System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
+ return 0;
}
- public void runForceDexOpt() {
+ public int runForceDexOpt() {
final String packageName = nextArg();
try {
mPm.forceDexOpt(packageName);
+ return 0;
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
- private void runUninstall() throws RemoteException {
+ private int runUninstall() throws RemoteException {
int flags = 0;
int userId = UserHandle.USER_ALL;
@@ -1277,11 +1289,11 @@ public final class Pm {
} else {
showUsage();
System.err.println("Error: Invalid user: " + param);
- return;
+ return 1;
}
} else {
System.err.println("Error: Unknown option: " + opt);
- return;
+ return 1;
}
}
@@ -1289,7 +1301,7 @@ public final class Pm {
if (pkg == null) {
System.err.println("Error: no package specified");
showUsage();
- return;
+ return 1;
}
if (userId == UserHandle.USER_ALL) {
@@ -1302,11 +1314,11 @@ public final class Pm {
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
- return;
+ return 1;
}
if (info == null) {
System.err.println("Failure - not installed for " + userId);
- return;
+ return 1;
}
final boolean isSystem =
(info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
@@ -1326,10 +1338,12 @@ public final class Pm {
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
System.out.println("Success");
+ return 0;
} else {
Log.e(TAG, "Failure details: " + result.getExtras());
- System.out.println("Failure ["
+ System.err.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+ return 1;
}
}
@@ -1347,7 +1361,7 @@ public final class Pm {
}
}
- private void runClear() {
+ private int runClear() {
int userId = 0;
String option = nextOption();
if (option != null && option.equals("--user")) {
@@ -1355,7 +1369,7 @@ public final class Pm {
if (optionData == null || !isNumber(optionData)) {
System.err.println("Error: no USER_ID specified");
showUsage();
- return;
+ return 1;
} else {
userId = Integer.parseInt(optionData);
}
@@ -1365,7 +1379,7 @@ public final class Pm {
if (pkg == null) {
System.err.println("Error: no package specified");
showUsage();
- return;
+ return 1;
}
ClearDataObserver obs = new ClearDataObserver();
@@ -1381,13 +1395,16 @@ public final class Pm {
}
if (obs.result) {
- System.err.println("Success");
+ System.out.println("Success");
+ return 0;
} else {
System.err.println("Failed");
+ return 1;
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
@@ -1416,7 +1433,7 @@ public final class Pm {
return true;
}
- private void runSetEnabledSetting(int state) {
+ private int runSetEnabledSetting(int state) {
int userId = 0;
String option = nextOption();
if (option != null && option.equals("--user")) {
@@ -1424,7 +1441,7 @@ public final class Pm {
if (optionData == null || !isNumber(optionData)) {
System.err.println("Error: no USER_ID specified");
showUsage();
- return;
+ return 1;
} else {
userId = Integer.parseInt(optionData);
}
@@ -1434,34 +1451,38 @@ public final class Pm {
if (pkg == null) {
System.err.println("Error: no package or component specified");
showUsage();
- return;
+ return 1;
}
ComponentName cn = ComponentName.unflattenFromString(pkg);
if (cn == null) {
try {
mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
"shell:" + android.os.Process.myUid());
- System.err.println("Package " + pkg + " new state: "
+ System.out.println("Package " + pkg + " new state: "
+ enabledSettingToString(
mPm.getApplicationEnabledSetting(pkg, userId)));
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
} else {
try {
mPm.setComponentEnabledSetting(cn, state, 0, userId);
- System.err.println("Component " + cn.toShortString() + " new state: "
+ System.out.println("Component " + cn.toShortString() + " new state: "
+ enabledSettingToString(
mPm.getComponentEnabledSetting(cn, userId)));
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
}
- private void runSetHiddenSetting(boolean state) {
+ private int runSetHiddenSetting(boolean state) {
int userId = 0;
String option = nextOption();
if (option != null && option.equals("--user")) {
@@ -1469,7 +1490,7 @@ public final class Pm {
if (optionData == null || !isNumber(optionData)) {
System.err.println("Error: no USER_ID specified");
showUsage();
- return;
+ return 1;
} else {
userId = Integer.parseInt(optionData);
}
@@ -1479,30 +1500,32 @@ public final class Pm {
if (pkg == null) {
System.err.println("Error: no package or component specified");
showUsage();
- return;
+ return 1;
}
try {
mPm.setApplicationHiddenSettingAsUser(pkg, state, userId);
- System.err.println("Package " + pkg + " new hidden state: "
+ System.out.println("Package " + pkg + " new hidden state: "
+ mPm.getApplicationHiddenSettingAsUser(pkg, userId));
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
}
}
- private void runGrantRevokePermission(boolean grant) {
+ private int runGrantRevokePermission(boolean grant) {
String pkg = nextArg();
if (pkg == null) {
System.err.println("Error: no package specified");
showUsage();
- return;
+ return 1;
}
String perm = nextArg();
if (perm == null) {
System.err.println("Error: no permission specified");
showUsage();
- return;
+ return 1;
}
try {
if (grant) {
@@ -1510,41 +1533,49 @@ public final class Pm {
} else {
mPm.revokePermission(pkg, perm);
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
} catch (IllegalArgumentException e) {
System.err.println("Bad argument: " + e.toString());
showUsage();
+ return 1;
} catch (SecurityException e) {
System.err.println("Operation not allowed: " + e.toString());
+ return 1;
}
}
- private void runSetPermissionEnforced() {
+ private int runSetPermissionEnforced() {
final String permission = nextArg();
if (permission == null) {
System.err.println("Error: no permission specified");
showUsage();
- return;
+ return 1;
}
final String enforcedRaw = nextArg();
if (enforcedRaw == null) {
System.err.println("Error: no enforcement specified");
showUsage();
- return;
+ return 1;
}
final boolean enforced = Boolean.parseBoolean(enforcedRaw);
try {
mPm.setPermissionEnforced(permission, enforced);
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
} catch (IllegalArgumentException e) {
System.err.println("Bad argument: " + e.toString());
showUsage();
+ return 1;
} catch (SecurityException e) {
System.err.println("Operation not allowed: " + e.toString());
+ return 1;
}
}
@@ -1563,12 +1594,12 @@ public final class Pm {
}
- private void runTrimCaches() {
+ private int runTrimCaches() {
String size = nextArg();
if (size == null) {
System.err.println("Error: no size specified");
showUsage();
- return;
+ return 1;
}
int len = size.length();
long multiplier = 1;
@@ -1583,7 +1614,7 @@ public final class Pm {
} else {
System.err.println("Invalid suffix: " + c);
showUsage();
- return;
+ return 1;
}
size = size.substring(0, len-1);
}
@@ -1593,7 +1624,7 @@ public final class Pm {
} catch (NumberFormatException e) {
System.err.println("Error: expected number at: " + size);
showUsage();
- return;
+ return 1;
}
ClearDataObserver obs = new ClearDataObserver();
try {
@@ -1606,14 +1637,18 @@ public final class Pm {
}
}
}
+ return 0;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
+ return 1;
} catch (IllegalArgumentException e) {
System.err.println("Bad argument: " + e.toString());
showUsage();
+ return 1;
} catch (SecurityException e) {
System.err.println("Operation not allowed: " + e.toString());
+ return 1;
}
}
@@ -1621,7 +1656,7 @@ public final class Pm {
* Displays the package file for a package.
* @param pckg
*/
- private void displayPackageFilePath(String pckg) {
+ private int displayPackageFilePath(String pckg) {
try {
PackageInfo info = mPm.getPackageInfo(pckg, 0, 0);
if (info != null && info.applicationInfo != null) {
@@ -1632,12 +1667,14 @@ public final class Pm {
System.out.print("package:");
System.out.println(splitSourceDir);
}
+ return 0;
}
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
}
+ return 1;
}
private Resources getResources(PackageItemInfo pii) {
@@ -1752,7 +1789,7 @@ public final class Pm {
return arg;
}
- private static void showUsage() {
+ private static int showUsage() {
System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
System.err.println(" pm list permission-groups");
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
@@ -1873,5 +1910,6 @@ public final class Pm {
System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
System.err.println(" deleting all data associated with that user");
System.err.println("");
+ return 1;
}
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 7894887..ecf19c7 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -133,16 +133,17 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
return;
}
mAreViewsReady = true;
+ final ViewGroup decor = getDecor();
// Ensure the views have been laid out before capturing the views -- we need the epicenter.
- if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
+ if (decor == null || (decor.isAttachedToWindow() &&
+ (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) {
viewsReady(sharedElements);
} else {
- final View sharedElement = sharedElements.valueAt(0);
- sharedElement.getViewTreeObserver()
+ decor.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
+ decor.getViewTreeObserver().removeOnPreDrawListener(this);
viewsReady(sharedElements);
return true;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 369efac..c54a5ba 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6629,7 +6629,8 @@ public final class Settings {
WIFI_NUM_OPEN_NETWORKS_KEPT,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
- DOCK_AUDIO_MEDIA_ENABLED
+ DOCK_AUDIO_MEDIA_ENABLED,
+ LOW_POWER_MODE_TRIGGER_LEVEL
};
// Populated lazily, guarded by class object:
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e4f95a4..1d09696 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3109,6 +3109,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private MatchLabelForPredicate mMatchLabelForPredicate;
/**
+ * Specifies a view before which this one is visited in accessibility traversal.
+ */
+ private int mAccessibilityTraversalBeforeId = NO_ID;
+
+ /**
+ * Specifies a view after which this one is visited in accessibility traversal.
+ */
+ private int mAccessibilityTraversalAfterId = NO_ID;
+
+ /**
* Predicate for matching a view by its id.
*/
private MatchIdPredicate mMatchIdPredicate;
@@ -3888,6 +3898,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case com.android.internal.R.styleable.View_contentDescription:
setContentDescription(a.getString(attr));
break;
+ case com.android.internal.R.styleable.View_accessibilityTraversalBefore:
+ setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID));
+ break;
+ case com.android.internal.R.styleable.View_accessibilityTraversalAfter:
+ setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID));
+ break;
case com.android.internal.R.styleable.View_labelFor:
setLabelFor(a.getResourceId(attr, NO_ID));
break;
@@ -5611,6 +5627,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (rootView == null) {
rootView = this;
}
+
View label = rootView.findLabelForView(this, mID);
if (label != null) {
info.setLabeledBy(label);
@@ -5639,6 +5656,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ if (mAccessibilityTraversalBeforeId != View.NO_ID) {
+ View rootView = getRootView();
+ if (rootView == null) {
+ rootView = this;
+ }
+ View next = rootView.findViewInsideOutShouldExist(this,
+ mAccessibilityTraversalBeforeId);
+ if (next != null) {
+ info.setTraversalBefore(next);
+ }
+ }
+
+ if (mAccessibilityTraversalAfterId != View.NO_ID) {
+ View rootView = getRootView();
+ if (rootView == null) {
+ rootView = this;
+ }
+ View next = rootView.findViewInsideOutShouldExist(this,
+ mAccessibilityTraversalAfterId);
+ if (next != null) {
+ info.setTraversalAfter(next);
+ }
+ }
+
info.setVisibleToUser(isVisibleToUser());
info.setPackageName(mContext.getPackageName());
@@ -6043,6 +6084,94 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Sets the id of a view before which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of this view before the content of the one
+ * it precedes. For example, if view B is set to be before view A, then a screen-reader
+ * will traverse the entire content of B before traversing the entire content of A,
+ * regardles of what traversal strategy it is using.
+ * <p>
+ * Views that do not have specified before/after relationships are traversed in order
+ * determined by the screen-reader.
+ * </p>
+ * <p>
+ * Setting that this view is before a view that is not important for accessibility
+ * or if this view is not important for accessibility will have no effect as the
+ * screen-reader is not aware of unimportant views.
+ * </p>
+ *
+ * @param beforeId The id of a view this one precedes in accessibility traversal.
+ *
+ * @attr ref android.R.styleable#View_accessibilityTraversalBefore
+ *
+ * @see #setImportantForAccessibility(int)
+ */
+ @RemotableViewMethod
+ public void setAccessibilityTraversalBefore(int beforeId) {
+ if (mAccessibilityTraversalBeforeId == beforeId) {
+ return;
+ }
+ mAccessibilityTraversalBeforeId = beforeId;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+
+ /**
+ * Gets the id of a view before which this one is visited in accessibility traversal.
+ *
+ * @return The id of a view this one precedes in accessibility traversal if
+ * specified, otherwise {@link #NO_ID}.
+ *
+ * @see #setAccessibilityTraversalBefore(int)
+ */
+ public int getAccessibilityTraversalBefore() {
+ return mAccessibilityTraversalBeforeId;
+ }
+
+ /**
+ * Sets the id of a view after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other view before the content of this
+ * one. For example, if view B is set to be after view A, then a screen-reader
+ * will traverse the entire content of A before traversing the entire content of B,
+ * regardles of what traversal strategy it is using.
+ * <p>
+ * Views that do not have specified before/after relationships are traversed in order
+ * determined by the screen-reader.
+ * </p>
+ * <p>
+ * Setting that this view is after a view that is not important for accessibility
+ * or if this view is not important for accessibility will have no effect as the
+ * screen-reader is not aware of unimportant views.
+ * </p>
+ *
+ * @param afterId The id of a view this one succedees in accessibility traversal.
+ *
+ * @attr ref android.R.styleable#View_accessibilityTraversalAfter
+ *
+ * @see #setImportantForAccessibility(int)
+ */
+ @RemotableViewMethod
+ public void setAccessibilityTraversalAfter(int afterId) {
+ if (mAccessibilityTraversalAfterId == afterId) {
+ return;
+ }
+ mAccessibilityTraversalAfterId = afterId;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+
+ /**
+ * Gets the id of a view after which this one is visited in accessibility traversal.
+ *
+ * @return The id of a view this one succeedes in accessibility traversal if
+ * specified, otherwise {@link #NO_ID}.
+ *
+ * @see #setAccessibilityTraversalAfter(int)
+ */
+ public int getAccessibilityTraversalAfter() {
+ return mAccessibilityTraversalAfterId;
+ }
+
+ /**
* Gets the id of a view for which this view serves as a label for
* accessibility purposes.
*
@@ -6061,11 +6190,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@RemotableViewMethod
public void setLabelFor(int id) {
+ if (mLabelForId == id) {
+ return;
+ }
mLabelForId = id;
if (mLabelForId != View.NO_ID
&& mID == View.NO_ID) {
mID = generateViewId();
}
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 3987fbc..b5afdf7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -547,6 +547,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private long mParentNodeId = ROOT_NODE_ID;
private long mLabelForId = ROOT_NODE_ID;
private long mLabeledById = ROOT_NODE_ID;
+ private long mTraversalBefore = ROOT_NODE_ID;
+ private long mTraversalAfter = ROOT_NODE_ID;
private int mBooleanProperties;
private final Rect mBoundsInParent = new Rect();
@@ -1046,6 +1048,126 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalBefore(android.view.View)
+ * @see #setTraversalBefore(android.view.View, int)
+ */
+ public AccessibilityNodeInfo getTraversalBefore() {
+ enforceSealed();
+ return getNodeForAccessibilityId(mTraversalBefore);
+ }
+
+ /**
+ * Sets the view before whose node this one should be visited during traversal. A
+ * screen-reader must visit the content of this node before the content of the one
+ * it precedes.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The view providing the preceding node.
+ *
+ * @see #getTraversalBefore()
+ */
+ public void setTraversalBefore(View view) {
+ setTraversalBefore(view, UNDEFINED_ITEM_ID);
+ }
+
+ /**
+ * Sets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ * The successor is a virtual descendant of the given <code>root</code>. If
+ * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
+ * as the successor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalBefore(View root, int virtualDescendantId) {
+ enforceNotSealed();
+ final int rootAccessibilityViewId = (root != null)
+ ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+ mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ }
+
+ /**
+ * Gets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalAfter(android.view.View)
+ * @see #setTraversalAfter(android.view.View, int)
+ */
+ public AccessibilityNodeInfo getTraversalAfter() {
+ enforceSealed();
+ return getNodeForAccessibilityId(mTraversalAfter);
+ }
+
+ /**
+ * Sets the view whose node is visited after this one in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The previous view.
+ *
+ * @see #getTraversalAfter()
+ */
+ public void setTraversalAfter(View view) {
+ setTraversalAfter(view, UNDEFINED_ITEM_ID);
+ }
+
+ /**
+ * Sets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
+ * the root is set as the predecessor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalAfter(View root, int virtualDescendantId) {
+ enforceNotSealed();
+ final int rootAccessibilityViewId = (root != null)
+ ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+ mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ }
+
+ /**
* Sets the maximum text length, or -1 for no limit.
* <p>
* Typically used to indicate that an editable text field has a limit on
@@ -1229,13 +1351,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
- if (!canPerformRequestOverConnection(mParentNodeId)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mParentNodeId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mParentNodeId);
}
/**
@@ -2055,13 +2171,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabelFor() {
enforceSealed();
- if (!canPerformRequestOverConnection(mLabelForId)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabelForId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mLabelForId);
}
/**
@@ -2113,13 +2223,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabeledBy() {
enforceSealed();
- if (!canPerformRequestOverConnection(mLabeledById)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabeledById, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mLabeledById);
}
/**
@@ -2453,6 +2557,9 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeLong(mParentNodeId);
parcel.writeLong(mLabelForId);
parcel.writeLong(mLabeledById);
+ parcel.writeLong(mTraversalBefore);
+ parcel.writeLong(mTraversalAfter);
+
parcel.writeInt(mConnectionId);
final LongArray childIds = mChildNodeIds;
@@ -2571,6 +2678,8 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = other.mParentNodeId;
mLabelForId = other.mLabelForId;
mLabeledById = other.mLabeledById;
+ mTraversalBefore = other.mTraversalBefore;
+ mTraversalAfter = other.mTraversalAfter;
mWindowId = other.mWindowId;
mConnectionId = other.mConnectionId;
mBoundsInParent.set(other.mBoundsInParent);
@@ -2633,6 +2742,9 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = parcel.readLong();
mLabelForId = parcel.readLong();
mLabeledById = parcel.readLong();
+ mTraversalBefore = parcel.readLong();
+ mTraversalAfter = parcel.readLong();
+
mConnectionId = parcel.readInt();
final int childrenSize = parcel.readInt();
@@ -2725,6 +2837,8 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = ROOT_NODE_ID;
mLabelForId = ROOT_NODE_ID;
mLabeledById = ROOT_NODE_ID;
+ mTraversalBefore = ROOT_NODE_ID;
+ mTraversalAfter = ROOT_NODE_ID;
mWindowId = UNDEFINED_ITEM_ID;
mConnectionId = UNDEFINED_CONNECTION_ID;
mMaxTextLength = -1;
@@ -2911,6 +3025,8 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
builder.append("; mParentNodeId: " + mParentNodeId);
+ builder.append("; traversalBefore: ").append(mTraversalBefore);
+ builder.append("; traversalAfter: ").append(mTraversalAfter);
int granularities = mMovementGranularities;
builder.append("; MovementGranularities: [");
@@ -2963,6 +3079,16 @@ public class AccessibilityNodeInfo implements Parcelable {
return builder.toString();
}
+ private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
+ if (!canPerformRequestOverConnection(accessibilityId)) {
+ return null;
+ }
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+ | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ }
+
/**
* A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
* Each action has a unique id that is mandatory and optional data.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 80f364b..dd7fa18 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2528,6 +2528,26 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to calling {@link android.view.View#setAccessibilityTraversalBefore(int)}.
+ *
+ * @param viewId The id of the view whose before view in accessibility traversal to set.
+ * @param nextId The id of the next in the accessibility traversal.
+ **/
+ public void setAccessibilityTraversalBefore(int viewId, int nextId) {
+ setInt(viewId, "setAccessibilityTraversalBefore", nextId);
+ }
+
+ /**
+ * Equivalent to calling {@link android.view.View#setAccessibilityTraversalAfter(int)}.
+ *
+ * @param viewId The id of the view whose after view in accessibility traversal to set.
+ * @param nextId The id of the next in the accessibility traversal.
+ **/
+ public void setAccessibilityTraversalAfter(int viewId, int nextId) {
+ setInt(viewId, "setAccessibilityTraversalAfter", nextId);
+ }
+
+ /**
* Equivalent to calling View.setLabelFor(int).
*
* @param viewId The id of the view whose property to set.
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ccffa19..7df76e5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -278,9 +278,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
- rdl.setOnClickOutsideListener(new View.OnClickListener() {
+ rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
@Override
- public void onClick(View v) {
+ public void onDismissed() {
finish();
}
});
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 375822f..25b4945 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -63,18 +63,22 @@ public class ResolverDrawerLayout extends ViewGroup {
private float mCollapseOffset;
private int mCollapsibleHeight;
+ private int mUncollapsibleHeight;
private int mTopOffset;
private boolean mIsDragging;
private boolean mOpenOnClick;
private boolean mOpenOnLayout;
+ private boolean mDismissOnScrollerFinished;
private final int mTouchSlop;
private final float mMinFlingVelocity;
private final OverScroller mScroller;
private final VelocityTracker mVelocityTracker;
- private OnClickListener mClickOutsideListener;
+ private OnDismissedListener mOnDismissedListener;
+ private RunOnDismissedListener mRunOnDismissedListener;
+
private float mInitialTouchX;
private float mInitialTouchY;
private float mLastTouchY;
@@ -143,8 +147,8 @@ public class ResolverDrawerLayout extends ViewGroup {
return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
}
- public void setOnClickOutsideListener(OnClickListener listener) {
- mClickOutsideListener = listener;
+ public void setOnDismissedListener(OnDismissedListener listener) {
+ mOnDismissedListener = listener;
}
@Override
@@ -194,7 +198,7 @@ public class ResolverDrawerLayout extends ViewGroup {
}
if (mIsDragging) {
- mScroller.abortAnimation();
+ abortAnimation();
}
return mIsDragging || mOpenOnClick;
}
@@ -213,12 +217,9 @@ public class ResolverDrawerLayout extends ViewGroup {
mInitialTouchX = x;
mInitialTouchY = mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
- if (findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
- mClickOutsideListener != null) {
- mIsDragging = handled = true;
- }
- handled |= mCollapsibleHeight > 0;
- mScroller.abortAnimation();
+ mIsDragging = findChildUnder(mInitialTouchX, mInitialTouchY) != null;
+ handled = (!mIsDragging && mOnDismissedListener != null) || mCollapsibleHeight > 0;
+ abortAnimation();
}
break;
@@ -264,11 +265,12 @@ public class ResolverDrawerLayout extends ViewGroup {
break;
case MotionEvent.ACTION_UP: {
+ final boolean wasDragging = mIsDragging;
mIsDragging = false;
- if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+ if (!wasDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
findChildUnder(ev.getX(), ev.getY()) == null) {
- if (mClickOutsideListener != null) {
- mClickOutsideListener.onClick(this);
+ if (mOnDismissedListener != null) {
+ dispatchOnDismissed();
resetTouch();
return true;
}
@@ -281,7 +283,13 @@ public class ResolverDrawerLayout extends ViewGroup {
mVelocityTracker.computeCurrentVelocity(1000);
final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
if (Math.abs(yvel) > mMinFlingVelocity) {
- smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ if (mOnDismissedListener != null
+ && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ }
} else {
smoothScrollTo(
mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
@@ -327,17 +335,27 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public void computeScroll() {
super.computeScroll();
- if (!mScroller.isFinished()) {
- final boolean keepGoing = mScroller.computeScrollOffset();
+ if (mScroller.computeScrollOffset()) {
+ final boolean keepGoing = !mScroller.isFinished();
performDrag(mScroller.getCurrY() - mCollapseOffset);
if (keepGoing) {
postInvalidateOnAnimation();
+ } else if (mDismissOnScrollerFinished && mOnDismissedListener != null) {
+ mRunOnDismissedListener = new RunOnDismissedListener();
+ post(mRunOnDismissedListener);
}
}
}
+ private void abortAnimation() {
+ mScroller.abortAnimation();
+ mRunOnDismissedListener = null;
+ mDismissOnScrollerFinished = false;
+ }
+
private float performDrag(float dy) {
- final float newPos = Math.max(0, Math.min(mCollapseOffset + dy, mCollapsibleHeight));
+ final float newPos = Math.max(0, Math.min(mCollapseOffset + dy,
+ mCollapsibleHeight + mUncollapsibleHeight));
if (newPos != mCollapseOffset) {
dy = newPos - mCollapseOffset;
final int childCount = getChildCount();
@@ -356,11 +374,18 @@ public class ResolverDrawerLayout extends ViewGroup {
return 0;
}
- private void smoothScrollTo(int yOffset, float velocity) {
- if (getMaxCollapsedHeight() == 0) {
- return;
+ void dispatchOnDismissed() {
+ if (mOnDismissedListener != null) {
+ mOnDismissedListener.onDismissed();
}
- mScroller.abortAnimation();
+ if (mRunOnDismissedListener != null) {
+ removeCallbacks(mRunOnDismissedListener);
+ mRunOnDismissedListener = null;
+ }
+ }
+
+ private void smoothScrollTo(int yOffset, float velocity) {
+ abortAnimation();
final int sy = (int) mCollapseOffset;
int dy = yOffset - sy;
if (dy == 0) {
@@ -490,6 +515,7 @@ public class ResolverDrawerLayout extends ViewGroup {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnTouchModeChangeListener(mTouchModeChangeListener);
+ abortAnimation();
}
@Override
@@ -585,6 +611,7 @@ public class ResolverDrawerLayout extends ViewGroup {
mCollapsibleHeight = Math.max(0,
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
+ mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
if (isLaidOut()) {
mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
@@ -734,4 +761,15 @@ public class ResolverDrawerLayout extends ViewGroup {
}
};
}
+
+ public interface OnDismissedListener {
+ public void onDismissed();
+ }
+
+ private class RunOnDismissedListener implements Runnable {
+ @Override
+ public void run() {
+ dispatchOnDismissed();
+ }
+ }
}
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 5f60c9e..2b756e2 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -19,6 +19,9 @@
#include "fpdfview.h"
#include "fpdfedit.h"
#include "fpdfsave.h"
+#include "fsdk_rendercontext.h"
+#include "fpdf_transformpage.h"
+#include "SkMatrix.h"
#include <android_runtime/AndroidRuntime.h>
#include <vector>
@@ -29,6 +32,20 @@
namespace android {
+enum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP};
+
+static struct {
+ jfieldID x;
+ jfieldID y;
+} gPointClassInfo;
+
+static struct {
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
static Mutex sLock;
static int sUnmatchedInitRequestCount = 0;
@@ -144,18 +161,201 @@ static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
}
}
+static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return;
+ }
+
+ CFX_AffineMatrix matrix;
+
+ SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
+
+ SkScalar transformValues[6];
+ skTransform->asAffine(transformValues);
+
+ // PDF's coordinate system origin is left-bottom while in graphics it
+ // is the top-left. So, translate the PDF coordinates to ours.
+ matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight());
+
+ // Apply the transformation what was created in our coordinates.
+ matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+ transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+ transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
+
+ // Translate the result back to PDF coordinates.
+ matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight());
+
+ FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
+ FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+ FPDFPage_TransFormWithClip(page, &transform, &clip);
+
+ FPDF_ClosePage(page);
+}
+
+static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+ jint pageIndex, jobject outSize) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return;
+ }
+
+ env->SetIntField(outSize, gPointClassInfo.x, width);
+ env->SetIntField(outSize, gPointClassInfo.y, height);
+
+ FPDF_ClosePage(page);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ PageBox pageBox, jobject outBox) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return false;
+ }
+
+ float left;
+ float top;
+ float right;
+ float bottom;
+
+ const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
+ ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
+ : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
+
+ FPDF_ClosePage(page);
+
+ if (!success) {
+ return false;
+ }
+
+ env->SetIntField(outBox, gRectClassInfo.left, (int) left);
+ env->SetIntField(outBox, gRectClassInfo.top, (int) top);
+ env->SetIntField(outBox, gRectClassInfo.right, (int) right);
+ env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom);
+
+ return true;
+}
+
+static jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject outMediaBox) {
+ const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA,
+ outMediaBox);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject outMediaBox) {
+ const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP,
+ outMediaBox);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ PageBox pageBox, jobject box) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return;
+ }
+
+ const int left = env->GetIntField(box, gRectClassInfo.left);
+ const int top = env->GetIntField(box, gRectClassInfo.top);
+ const int right = env->GetIntField(box, gRectClassInfo.right);
+ const int bottom = env->GetIntField(box, gRectClassInfo.bottom);
+
+ if (pageBox == PAGE_BOX_MEDIA) {
+ FPDFPage_SetMediaBox(page, left, top, right, bottom);
+ } else {
+ FPDFPage_SetCropBox(page, left, top, right, bottom);
+ }
+
+ FPDF_ClosePage(page);
+}
+
+static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject mediaBox) {
+ nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox);
+}
+
+static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject mediaBox) {
+ nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
+}
+
static JNINativeMethod gPdfEditor_Methods[] = {
{"nativeOpen", "(IJ)J", (void*) nativeOpen},
{"nativeClose", "(J)V", (void*) nativeClose},
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
{"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
- {"nativeWrite", "(JI)V", (void*) nativeWrite}
+ {"nativeWrite", "(JI)V", (void*) nativeWrite},
+ {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip},
+ {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize},
+ {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+ {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox},
+ {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox},
+ {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox},
+ {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox}
};
int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
- return android::AndroidRuntime::registerNativeMethods(
+ const int result = android::AndroidRuntime::registerNativeMethods(
env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
NELEM(gPdfEditor_Methods));
+
+ jclass pointClass = env->FindClass("android/graphics/Point");
+ gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I");
+ gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I");
+
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I");
+ gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I");
+ gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I");
+ gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I");
+
+ return result;
};
};
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c4131b3..91a8598 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2363,6 +2363,18 @@
representation this attribute can be used for providing such. -->
<attr name="contentDescription" format="string" localization="suggested" />
+ <!-- Sets the id of a view before which this one is visited in accessibility traversal.
+ A screen-reader must visit the content of this view before the content of the one
+ it precedes.
+ @see android.view.View#setAccessibilityTraversalBefore(int)} -->
+ <attr name="accessibilityTraversalBefore" format="integer" />
+
+ <!-- Sets the id of a view after which this one is visited in accessibility traversal.
+ A screen-reader must visit the content of the other view before the content of
+ this one.
+ @see android.view.View#setAccessibilityTraversalAfter(int)} -->
+ <attr name="accessibilityTraversalAfter" format="integer" />
+
<!-- Name of the method in this View's context to invoke when the view is
clicked. This name must correspond to a public method that takes
exactly one parameter of type View. For instance, if you specify
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c0b7fd0..c0a5ab2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2597,5 +2597,7 @@
<public type="attr" name="resizeClip"/>
<public type="attr" name="collapseContentDescription"/>
+ <public type="attr" name="accessibilityTraversalBefore" />
+ <public type="attr" name="accessibilityTraversalAfter" />
</resources>
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 9837139..0b84d29 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -17,6 +17,10 @@
package android.graphics.pdf;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.OsConstants;
@@ -98,6 +102,109 @@ public final class PdfEditor {
}
/**
+ * Sets a transformation and clip for a given page. The transformation matrix if
+ * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If
+ * the clip is null, then no clipping is performed.
+ *
+ * @param pageIndex The page whose transform to set.
+ * @param transform The transformation to apply.
+ * @param clip The clip to apply.
+ */
+ public void setTransformAndClip(int pageIndex, @Nullable Matrix transform,
+ @Nullable Rect clip) {
+ throwIfClosed();
+ throwIfPageNotInDocument(pageIndex);
+ throwIfNotNullAndNotAfine(transform);
+ if (transform == null) {
+ transform = Matrix.IDENTITY_MATRIX;
+ }
+ if (clip == null) {
+ Point size = new Point();
+ getPageSize(pageIndex, size);
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ 0, 0, size.x, size.y);
+ } else {
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ clip.left, clip.top, clip.right, clip.bottom);
+ }
+ }
+
+ /**
+ * Gets the size of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outSize The size output.
+ */
+ public void getPageSize(int pageIndex, @NonNull Point outSize) {
+ throwIfClosed();
+ throwIfOutSizeNull(outSize);
+ throwIfPageNotInDocument(pageIndex);
+ nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+ }
+
+ /**
+ * Gets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outMediaBox The media box output.
+ */
+ public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) {
+ throwIfClosed();
+ throwIfOutMediaBoxNull(outMediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+ }
+
+ /**
+ * Sets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param mediaBox The media box.
+ */
+ public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) {
+ throwIfClosed();
+ throwIfMediaBoxNull(mediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+ }
+
+ /**
+ * Gets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outCropBox The crop box output.
+ */
+ public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) {
+ throwIfClosed();
+ throwIfOutCropBoxNull(outCropBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+ }
+
+ /**
+ * Sets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param cropBox The crop box.
+ */
+ public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) {
+ throwIfClosed();
+ throwIfCropBoxNull(cropBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+ }
+
+ /**
+ * Gets whether the document prefers to be scaled for printing.
+ *
+ * @return Whether to scale the document.
+ */
+ public boolean shouldScaleForPrinting() {
+ throwIfClosed();
+ return nativeScaleForPrinting(mNativeDocument);
+ }
+
+ /**
* Writes the PDF file to the provided destination.
* <p>
* <strong>Note:</strong> This method takes ownership of the passed in file
@@ -154,9 +261,57 @@ public final class PdfEditor {
}
}
+ private void throwIfNotNullAndNotAfine(Matrix matrix) {
+ if (matrix != null && !matrix.isAffine()) {
+ throw new IllegalStateException("Matrix must be afine");
+ }
+ }
+
+ private void throwIfOutSizeNull(Point outSize) {
+ if (outSize == null) {
+ throw new NullPointerException("outSize cannot be null");
+ }
+ }
+
+ private void throwIfOutMediaBoxNull(Rect outMediaBox) {
+ if (outMediaBox == null) {
+ throw new NullPointerException("outMediaBox cannot be null");
+ }
+ }
+
+ private void throwIfMediaBoxNull(Rect mediaBox) {
+ if (mediaBox == null) {
+ throw new NullPointerException("mediaBox cannot be null");
+ }
+ }
+
+ private void throwIfOutCropBoxNull(Rect outCropBox) {
+ if (outCropBox == null) {
+ throw new NullPointerException("outCropBox cannot be null");
+ }
+ }
+
+ private void throwIfCropBoxNull(Rect cropBox) {
+ if (cropBox == null) {
+ throw new NullPointerException("cropBox cannot be null");
+ }
+ }
+
private static native long nativeOpen(int fd, long size);
private static native void nativeClose(long documentPtr);
private static native int nativeGetPageCount(long documentPtr);
private static native int nativeRemovePage(long documentPtr, int pageIndex);
private static native void nativeWrite(long documentPtr, int fd);
+ private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex,
+ long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom);
+ private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize);
+ private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageCropBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeScaleForPrinting(long documentPtr);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
index b450ccb..01cabe1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
@@ -18,6 +18,7 @@ package com.android.printspooler.renderer;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
+import android.print.PrintAttributes;
/**
* Interface for communication with a remote pdf editor.
@@ -25,6 +26,7 @@ import android.print.PageRange;
interface IPdfEditor {
int openDocument(in ParcelFileDescriptor source);
void removePages(in PageRange[] pages);
+ void applyPrintAttributes(in PrintAttributes attributes);
void write(in ParcelFileDescriptor destination);
void closeDocument();
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 00e5051..0462e4d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -87,7 +87,7 @@ public final class PdfManipulationService extends Service {
}
mRenderer = new PdfRenderer(source);
return mRenderer.getPageCount();
- } catch (IOException|IllegalStateException e) {
+ } catch (IOException | IllegalStateException e) {
IoUtils.closeQuietly(source);
Log.e(LOG_TAG, "Cannot open file", e);
return MALFORMED_PDF_FILE_ERROR;
@@ -217,7 +217,7 @@ public final class PdfManipulationService extends Service {
}
mEditor = new PdfEditor(source);
return mEditor.getPageCount();
- } catch (IOException|IllegalStateException e) {
+ } catch (IOException | IllegalStateException e) {
IoUtils.closeQuietly(source);
Log.e(LOG_TAG, "Cannot open file", e);
throw new RemoteException(e.toString());
@@ -246,6 +246,111 @@ public final class PdfManipulationService extends Service {
}
@Override
+ public void applyPrintAttributes(PrintAttributes attributes) {
+ synchronized (mLock) {
+ throwIfNotOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "applyPrintAttributes()");
+ }
+
+ Rect mediaBox = new Rect();
+ Rect cropBox = new Rect();
+ Matrix transform = new Matrix();
+
+ final boolean contentPortrait = attributes.getMediaSize().isPortrait();
+
+ final boolean layoutDirectionRtl = getResources().getConfiguration()
+ .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+ // We do not want to rotate the media box, so take into account orientation.
+ final int dstWidthPts = contentPortrait
+ ? pointsFromMils(attributes.getMediaSize().getWidthMils())
+ : pointsFromMils(attributes.getMediaSize().getHeightMils());
+ final int dstHeightPts = contentPortrait
+ ? pointsFromMils(attributes.getMediaSize().getHeightMils())
+ : pointsFromMils(attributes.getMediaSize().getWidthMils());
+
+ final boolean scaleForPrinting = mEditor.shouldScaleForPrinting();
+
+ final int pageCount = mEditor.getPageCount();
+ for (int i = 0; i < pageCount; i++) {
+ if (!mEditor.getPageMediaBox(i, mediaBox)) {
+ Log.e(LOG_TAG, "Malformed PDF file");
+ return;
+ }
+
+ final int srcWidthPts = mediaBox.width();
+ final int srcHeightPts = mediaBox.height();
+
+ // Update the media box with the desired size.
+ mediaBox.right = dstWidthPts;
+ mediaBox.bottom = dstHeightPts;
+ mEditor.setPageMediaBox(i, mediaBox);
+
+ // Make sure content is top-left after media box resize.
+ transform.setTranslate(0, srcHeightPts - dstHeightPts);
+
+ // Rotate the content if in landscape.
+ if (!contentPortrait) {
+ transform.postRotate(270);
+ transform.postTranslate(0, dstHeightPts);
+ }
+
+ // Scale the content if document allows it.
+ final float scale;
+ if (scaleForPrinting) {
+ if (contentPortrait) {
+ scale = Math.min((float) dstWidthPts / srcWidthPts,
+ (float) dstHeightPts / srcHeightPts);
+ transform.postScale(scale, scale);
+ } else {
+ scale = Math.min((float) dstWidthPts / srcHeightPts,
+ (float) dstHeightPts / srcWidthPts);
+ transform.postScale(scale, scale, mediaBox.left, mediaBox.bottom);
+ }
+ } else {
+ scale = 1.0f;
+ }
+
+ // Update the crop box relatively to the media box change, if needed.
+ if (mEditor.getPageCropBox(i, cropBox)) {
+ cropBox.left = (int) (cropBox.left * scale + 0.5f);
+ cropBox.top = (int) (cropBox.top * scale + 0.5f);
+ cropBox.right = (int) (cropBox.right * scale + 0.5f);
+ cropBox.bottom = (int) (cropBox.bottom * scale + 0.5f);
+ cropBox.intersect(mediaBox);
+ mEditor.setPageCropBox(i, cropBox);
+ }
+
+ // If in RTL mode put the content in the logical top-right corner.
+ if (layoutDirectionRtl) {
+ final float dx = contentPortrait
+ ? dstWidthPts - (int) (srcWidthPts * scale + 0.5f) : 0;
+ final float dy = contentPortrait
+ ? 0 : - (dstHeightPts - (int) (srcWidthPts * scale + 0.5f));
+ transform.postTranslate(dx, dy);
+ }
+
+ // Adjust the physical margins if needed.
+ Margins minMargins = attributes.getMinMargins();
+ final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
+ final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
+ final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
+ final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
+
+ Rect clip = new Rect(mediaBox);
+ clip.left += paddingLeftPts;
+ clip.top += paddingTopPts;
+ clip.right -= paddingRightPts;
+ clip.bottom -= paddingBottomPts;
+
+ // Apply the accumulated transforms.
+ mEditor.setTransformAndClip(i, transform, clip);
+ }
+ }
+ }
+
+ @Override
public void write(ParcelFileDescriptor destination) throws RemoteException {
synchronized (mLock) {
try {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 15ea9a7..f361884 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -592,7 +592,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
mDestinationSpinner.post(new Runnable() {
@Override
public void run() {
- shredPagesAndFinish(uri);
+ transformDocumentAndFinish(uri);
}
});
} else if (resultCode == RESULT_CANCELED) {
@@ -922,7 +922,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
startCreateDocumentActivity();
} else {
- shredPagesAndFinish(null);
+ transformDocumentAndFinish(null);
}
}
@@ -1597,8 +1597,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
return true;
}
- private void shredPagesAndFinish(final Uri writeToUri) {
- new PageShredder(this, mPrintJob, mFileProvider, new Runnable() {
+ private void transformDocumentAndFinish(final Uri writeToUri) {
+ // If saving to PDF, apply the attibutes as we are acting as a print service.
+ PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter
+ ? mPrintJob.getAttributes() : null;
+ new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, new Runnable() {
@Override
public void run() {
if (writeToUri != null) {
@@ -1606,7 +1609,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
doFinish();
}
- }).shred();
+ }).transform();
}
private void doFinish() {
@@ -2329,7 +2332,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
}
- private static final class PageShredder implements ServiceConnection {
+ private static final class DocumentTransformer implements ServiceConnection {
private static final String TEMP_FILE_PREFIX = "print_job";
private static final String TEMP_FILE_EXTENSION = ".pdf";
@@ -2341,20 +2344,24 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
private final PageRange[] mPagesToShred;
+ private final PrintAttributes mAttributesToApply;
+
private final Runnable mCallback;
- public PageShredder(Context context, PrintJobInfo printJob,
- MutexFileProvider fileProvider, Runnable callback) {
+ public DocumentTransformer(Context context, PrintJobInfo printJob,
+ MutexFileProvider fileProvider, PrintAttributes attributes,
+ Runnable callback) {
mContext = context;
mPrintJob = printJob;
mFileProvider = fileProvider;
mCallback = callback;
mPagesToShred = computePagesToShred(mPrintJob);
+ mAttributesToApply = attributes;
}
- public void shred() {
+ public void transform() {
// If we have only the pages we want, done.
- if (mPagesToShred.length <= 0) {
+ if (mPagesToShred.length <= 0 && mAttributesToApply == null) {
mCallback.run();
return;
}
@@ -2376,14 +2383,14 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
// final and this code is the last one to touch
// them as shredding is the very last step, so the
// UI is not interactive at this point.
- shredPages(editor);
+ doTransform(editor);
updatePrintJob();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
- mContext.unbindService(PageShredder.this);
+ mContext.unbindService(DocumentTransformer.this);
mCallback.run();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -2394,7 +2401,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
/* do nothing */
}
- private void shredPages(IPdfEditor editor) {
+ private void doTransform(IPdfEditor editor) {
File tempFile = null;
ParcelFileDescriptor src = null;
ParcelFileDescriptor dst = null;
@@ -2413,6 +2420,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
// Drop the pages.
editor.removePages(mPagesToShred);
+ // Apply print attributes if needed.
+ if (mAttributesToApply != null) {
+ editor.applyPrintAttributes(mAttributesToApply);
+ }
+
// Write the modified PDF to a temp file.
tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION,
mContext.getCacheDir());