Merge change 4486 into donut
* changes:
Fixes #1107690. Updates javadoc for Intent.java, android:value -> android:name.
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index 22dd486..d4e669b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -64,22 +64,14 @@
}
BackupDataReader reader(fd);
+ bool done;
int type;
- while (reader.ReadNextHeader(&type) == 0) {
+ while (reader.ReadNextHeader(&done, &type) == 0) {
+ if (done) {
+ break;
+ }
switch (type) {
- case BACKUP_HEADER_APP_V1:
- {
- String8 packageName;
- int cookie;
- err = reader.ReadAppHeader(&packageName, &cookie);
- if (err == 0) {
- printf("App header: %s 0x%08x (%d)\n", packageName.string(), cookie, cookie);
- } else {
- printf("Error reading app header\n");
- }
- break;
- }
case BACKUP_HEADER_ENTITY_V1:
{
String8 key;
@@ -92,17 +84,6 @@
}
break;
}
- case BACKUP_FOOTER_APP_V1:
- {
- int cookie;
- err = reader.ReadAppFooter(&cookie);
- if (err == 0) {
- printf(" App footer: 0x%08x (%d)\n", cookie, cookie);
- } else {
- printf(" Error reading entity header\n");
- }
- break;
- }
default:
{
printf("Unknown chunk type: 0x%08x\n", type);
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
index e53cece..17dd060 100644
--- a/cmds/keystore/commands.c
+++ b/cmds/keystore/commands.c
@@ -1,5 +1,5 @@
/*
-** Copyright 2008, The Android Open Source Project
+** Copyright 2009, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@
return d;
}
-static int list_files(const char *dir, char reply[REPLY_MAX]) {
+static int list_files(const char *dir, char reply[REPLY_MAX])
+{
struct dirent *de;
DIR *d;
@@ -39,7 +40,9 @@
}
reply[0]=0;
while ((de = readdir(d))) {
- if (de->d_type != DT_REG) continue;
+ if (de->d_type != DT_DIR) continue;
+ if ((strcmp(DOT, de->d_name) == 0) ||
+ (strcmp(DOTDOT, de->d_name) == 0)) continue;
if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
LOGE("reply is too long(too many files under '%s'\n", dir);
@@ -50,31 +53,25 @@
return 0;
}
-static int copy_keyfile(const char *keystore, const char *srcfile) {
- int srcfd, dstfd;
- int length;
- char buf[2048];
- char dstfile[KEYNAME_LENGTH];
- const char *filename = strrchr(srcfile, '/');
+static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
+ int srcfd = -1, dstfd;
+ char buf[REPLY_MAX];
- strlcpy(dstfile, keystore, KEYNAME_LENGTH);
- strlcat(dstfile, "/", KEYNAME_LENGTH);
- if (strlcat(dstfile, filename ? filename + 1 : srcfile,
- KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
- LOGE("keyname is too long '%s'\n", srcfile);
- return -1;
- }
-
- if ((srcfd = open(srcfile, O_RDONLY)) == -1) {
- LOGE("Cannot open the original file '%s'\n", srcfile);
+ if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
+ LOGE("Cannot open the original file '%s'\n", src);
return -1;
}
if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
LOGE("Cannot open the destination file '%s'\n", dstfile);
return -1;
}
- while((length = read(srcfd, buf, 2048)) > 0) {
- write(dstfd, buf, length);
+ if (src_type == IS_FILE) {
+ int length;
+ while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
+ write(dstfd, buf, length);
+ }
+ } else {
+ write(dstfd, src, strlen(src));
}
close(srcfd);
close(dstfd);
@@ -82,60 +79,149 @@
return 0;
}
-static int install_key(const char *dir, const char *keyfile)
+static int install_key(const char *path, const char *certname, const char *src,
+ int src_is_file, char *dstfile)
{
struct dirent *de;
+ char fullpath[KEYNAME_LENGTH];
DIR *d;
- if ((d = open_keystore(dir)) == NULL) {
+ if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
+ >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", certname);
return -1;
}
- return copy_keyfile(dir, keyfile);
+
+ if ((d = open_keystore(fullpath)) == NULL) {
+ LOGE("Can not open the keystore '%s'\n", fullpath);
+ return -1;
+ }
+ closedir(d);
+ if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", certname);
+ return -1;
+ }
+ return copy_keyfile(src, src_is_file, fullpath);
}
-static int remove_key(const char *dir, const char *keyfile)
+static int get_key(const char *path, const char *keyname, const char *file,
+ char reply[REPLY_MAX])
{
- char dstfile[KEYNAME_LENGTH];
+ struct dirent *de;
+ char filename[KEYNAME_LENGTH];
+ int fd;
- strlcpy(dstfile, dir, KEYNAME_LENGTH);
- strlcat(dstfile, "/", KEYNAME_LENGTH);
- if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
- LOGE("keyname is too long '%s'\n", keyfile);
+ if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
+ >= KEYNAME_LENGTH) {
+ LOGE("cert name '%s' is too long.\n", keyname);
return -1;
}
- if (unlink(dstfile)) {
- LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno));
+
+ if ((fd = open(filename, O_RDONLY)) == -1) {
+ return -1;
+ }
+ close(fd);
+ strlcpy(reply, filename, REPLY_MAX);
+ return 0;
+}
+
+static int remove_key(const char *dir, const char *key)
+{
+ char dstfile[KEYNAME_LENGTH];
+ char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
+ CA_CERTIFICATE };
+ int i, count = 0;
+
+ for ( i = 0 ; i < 4 ; i++) {
+ if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
+ >= KEYNAME_LENGTH) {
+ LOGE("keyname is too long '%s'\n", key);
+ return -1;
+ }
+ if (unlink(dstfile) == 0) count++;
+ }
+
+ if (count == 0) {
+ LOGE("can not clean up '%s' keys or not exist\n", key);
+ return -1;
+ }
+
+ snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
+ if (rmdir(dstfile)) {
+ LOGE("can not clean up '%s' directory\n", key);
return -1;
}
return 0;
}
-int list_certs(char reply[REPLY_MAX])
+int list_user_certs(char reply[REPLY_MAX])
{
return list_files(CERTS_DIR, reply);
}
-int list_userkeys(char reply[REPLY_MAX])
+int list_ca_certs(char reply[REPLY_MAX])
{
- return list_files(USERKEYS_DIR, reply);
+ return list_files(CACERTS_DIR, reply);
}
-int install_cert(const char *certfile)
+int install_user_cert(const char *keyname, const char *cert, const char *key)
{
- return install_key(CERTS_DIR, certfile);
+ if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
+ return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
+ }
+ return -1;
}
-int install_userkey(const char *keyfile)
+int install_ca_cert(const char *keyname, const char *certfile)
{
- return install_key(USERKEYS_DIR, keyfile);
+ return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
}
-int remove_cert(const char *certfile)
+int install_p12_cert(const char *keyname, const char *certfile)
{
- return remove_key(CERTS_DIR, certfile);
+ return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
}
-int remove_userkey(const char *keyfile)
+int add_ca_cert(const char *keyname, const char *certificate)
{
- return remove_key(USERKEYS_DIR, keyfile);
+ return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
+ CA_CERTIFICATE);
+}
+
+int add_user_cert(const char *keyname, const char *certificate)
+{
+ return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
+ USER_CERTIFICATE);
+}
+
+int add_user_key(const char *keyname, const char *key)
+{
+ return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
+}
+
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
+{
+ return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
+}
+
+int get_user_cert(const char *keyname, char reply[REPLY_MAX])
+{
+ return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
+}
+
+int get_user_key(const char *keyname, char reply[REPLY_MAX])
+{
+ if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
+ return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
+ return 0;
+}
+
+int remove_user_cert(const char *key)
+{
+ return remove_key(CERTS_DIR, key);
+}
+
+int remove_ca_cert(const char *key)
+{
+ return remove_key(CACERTS_DIR, key);
}
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 5193b3d..df8d832 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -16,37 +16,89 @@
#include "keystore.h"
-
-static int do_list_certs(char **arg, char reply[REPLY_MAX])
+static inline int has_whitespace(char *name)
{
- return list_certs(reply);
+ if((strrchr(name, ' ') != NULL)) {
+ LOGE("'%s' contains whitespace character\n", name);
+ return 1;
+ }
+ return 0;
}
-static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
+static int do_list_user_certs(char **arg, char reply[REPLY_MAX])
{
- return list_userkeys(reply);
+ return list_user_certs(reply);
}
-static int do_install_cert(char **arg, char reply[REPLY_MAX])
+static int do_list_ca_certs(char **arg, char reply[REPLY_MAX])
{
- return install_cert(arg[0]); /* move the certificate to keystore */
+ return list_ca_certs(reply);
}
-static int do_remove_cert(char **arg, char reply[REPLY_MAX])
+static int do_install_user_cert(char **arg, char reply[REPLY_MAX])
{
- return remove_cert(arg[0]); /* certificate */
+ if (has_whitespace(arg[0])) return -1;
+ /* copy the certificate and key to keystore */
+ return install_user_cert(arg[0], arg[1], arg[2]);
}
-static int do_install_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_p12_cert(char **arg, char reply[REPLY_MAX])
{
- return install_userkey(arg[0]); /* move the certificate to keystore */
+ if (has_whitespace(arg[0])) return -1;
+ return install_p12_cert(arg[0], arg[1]);
}
-static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_ca_cert(char **arg, char reply[REPLY_MAX])
{
- return remove_userkey(arg[0]); /* userkey */
+ if (has_whitespace(arg[0])) return -1;
+ /* copy the certificate and key to keystore */
+ return install_ca_cert(arg[0], arg[1]);
}
+static int do_add_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+ if (has_whitespace(arg[0])) return -1;
+ return add_ca_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ if (has_whitespace(arg[0])) return -1;
+ return add_user_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_key(char **arg, char reply[REPLY_MAX])
+{
+ if (has_whitespace(arg[0])) return -1;
+ return add_user_key(arg[0], arg[1]);
+}
+
+static int do_get_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+ return get_ca_cert(arg[0], reply);
+}
+
+static int do_get_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ return get_user_cert(arg[0], reply);
+}
+
+static int do_get_user_key(char **arg, char reply[REPLY_MAX])
+{
+ return get_user_key(arg[0], reply);
+}
+
+static int do_remove_user_cert(char **arg, char reply[REPLY_MAX])
+{
+ return remove_user_cert(arg[0]);
+}
+
+static int do_remove_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+ return remove_ca_cert(arg[0]);
+}
+
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -55,12 +107,19 @@
struct cmdinfo cmds[] = {
- { "listcerts", 0, do_list_certs },
- { "listuserkeys", 0, do_list_userkeys },
- { "installcert", 1, do_install_cert },
- { "removecert", 1, do_remove_cert },
- { "installuserkey", 1, do_install_userkey },
- { "removeuserkey", 1, do_remove_userkey },
+ { "listcacerts", 0, do_list_ca_certs },
+ { "listusercerts", 0, do_list_user_certs },
+ { "installusercert", 3, do_install_user_cert },
+ { "installcacert", 2, do_install_ca_cert },
+ { "installp12cert", 2, do_install_p12_cert },
+ { "addusercert", 2, do_add_user_cert },
+ { "adduserkey", 2, do_add_user_key },
+ { "addcacert", 2, do_add_ca_cert },
+ { "getusercert", 1, do_get_user_cert },
+ { "getuserkey", 1, do_get_user_key },
+ { "getcacert", 1, do_get_ca_cert },
+ { "removecacert", 1, do_remove_ca_cert },
+ { "removeusercert", 1, do_remove_user_cert },
};
static int readx(int s, void *_buf, int count)
@@ -121,7 +180,7 @@
/* n is number of args (not counting arg[0]) */
arg[0] = cmd;
while (*cmd) {
- if (isspace(*cmd)) {
+ if (*cmd == CMD_DELIMITER) {
*cmd++ = 0;
n++;
arg[n] = cmd;
@@ -167,6 +226,7 @@
int fd, i;
short ret;
unsigned short count;
+ char delimiter[2] = { CMD_DELIMITER, 0 };
char buf[BUFFER_MAX]="";
fd = socket_local_client(SOCKET_PATH,
@@ -177,7 +237,7 @@
exit(1);
}
for(i = 0; i < argc; i++) {
- if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+ if (i > 0) strlcat(buf, delimiter, BUFFER_MAX);
if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
fprintf(stderr, "Arguments are too long\n");
exit(1);
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
index 35acf0b9..b9cb185 100644
--- a/cmds/keystore/keystore.h
+++ b/cmds/keystore/keystore.h
@@ -40,18 +40,35 @@
/* path of the keystore */
#define KEYSTORE_DIR_PREFIX "/data/misc/keystore"
-#define CERTS_DIR KEYSTORE_DIR_PREFIX "/certs"
-#define USERKEYS_DIR KEYSTORE_DIR_PREFIX "/userkeys"
+#define CERTS_DIR KEYSTORE_DIR_PREFIX "/keys"
+#define CACERTS_DIR KEYSTORE_DIR_PREFIX "/cacerts"
+#define CA_CERTIFICATE "ca.crt"
+#define USER_CERTIFICATE "user.crt"
+#define USER_P12_CERT "user.p12"
+#define USER_KEY "user.key"
+#define DOT "."
+#define DOTDOT ".."
-#define BUFFER_MAX 1024 /* input buffer for commands */
+#define BUFFER_MAX 4096 /* input buffer for commands */
#define TOKEN_MAX 8 /* max number of arguments in buffer */
-#define REPLY_MAX 1024 /* largest reply allowed */
+#define REPLY_MAX 4096 /* largest reply allowed */
+#define CMD_DELIMITER '\t'
#define KEYNAME_LENGTH 128
+#define IS_CONTENT 0
+#define IS_FILE 1
+
/* commands.c */
-int list_certs(char reply[REPLY_MAX]);
-int list_userkeys(char reply[REPLY_MAX]);
-int install_cert(const char *certfile);
-int install_userkey(const char *keyfile);
-int remove_cert(const char *certfile);
-int remove_userkey(const char *keyfile);
+int list_ca_certs(char reply[REPLY_MAX]);
+int list_user_certs(char reply[REPLY_MAX]);
+int install_user_cert(const char *certname, const char *cert, const char *key);
+int install_ca_cert(const char *certname, const char *cert);
+int install_p12_cert(const char *certname, const char *cert);
+int add_ca_cert(const char *certname, const char *content);
+int add_user_cert(const char *certname, const char *content);
+int add_user_key(const char *keyname, const char *content);
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_key(const char *keyname, char reply[REPLY_MAX]);
+int remove_user_cert(const char *certname);
+int remove_ca_cert(const char *certname);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2fe6471..3676594 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3217,7 +3217,7 @@
r.activity.getComponentName().getClassName());
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString()
+ "Activity " + safeToComponentShortString(r.intent)
+ " did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
@@ -3226,7 +3226,7 @@
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3241,7 +3241,7 @@
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3266,7 +3266,7 @@
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain child activities "
- + r.intent.getComponent().toShortString()
+ + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
@@ -3277,7 +3277,7 @@
r.activity.onDestroy();
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
- "Activity " + r.intent.getComponent().toShortString() +
+ "Activity " + safeToComponentShortString(r.intent) +
" did not call through to super.onDestroy()");
}
if (r.window != null) {
@@ -3287,10 +3287,9 @@
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
- ComponentName component = r.intent.getComponent();
- String name = component == null ? "[Unknown]" : component.toShortString();
throw new RuntimeException(
- "Unable to destroy activity " + name + ": " + e.toString(), e);
+ "Unable to destroy activity " + safeToComponentShortString(r.intent)
+ + ": " + e.toString(), e);
}
}
}
@@ -3299,6 +3298,11 @@
return r;
}
+ private static String safeToComponentShortString(Intent intent) {
+ ComponentName component = intent.getComponent();
+ return component == null ? "[Unknown]" : component.toShortString();
+ }
+
private final void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityRecord r = performDestroyActivity(token, finishing,
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9141c4c..b6c8385 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -35,11 +35,6 @@
import android.database.Cursor;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -153,15 +148,6 @@
private final WeakHashMap<String, Drawable> mOutsideDrawablesCache =
new WeakHashMap<String, Drawable>();
- // Objects we keep around for requesting location updates when the dialog is started
- // (and canceling them when the dialog is stopped). We don't actually make use of the
- // updates ourselves here, so the LocationListener is just a dummy which doesn't do
- // anything. We only do this here so that other suggest providers which wish to provide
- // location-based suggestions are more likely to get a good fresh location.
- private LocationManager mLocationManager;
- private LocationProvider mLocationProvider;
- private LocationListener mDummyLocationListener;
-
/**
* Constructor - fires it up and makes it look like the search UI.
*
@@ -240,37 +226,6 @@
mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- mLocationManager =
- (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
-
- if (mLocationManager != null) {
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_COARSE);
-
- String providerName = mLocationManager.getBestProvider(criteria, true);
-
- if (providerName != null) {
- mLocationProvider = mLocationManager.getProvider(providerName);
- }
-
- // Just a dumb listener that doesn't do anything - requesting location updates here
- // is only intended to give location-based suggestion providers the best chance
- // of getting a good fresh location.
- mDummyLocationListener = new LocationListener() {
- public void onLocationChanged(Location location) {
- }
-
- public void onProviderDisabled(String provider) {
- }
-
- public void onProviderEnabled(String provider) {
- }
-
- public void onStatusChanged(String provider, int status, Bundle extras) {
- }
- };
- }
}
/**
@@ -423,8 +378,6 @@
// receive broadcasts
getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
-
- startLocationUpdates();
}
/**
@@ -437,8 +390,6 @@
public void onStop() {
super.onStop();
- stopLocationUpdates();
-
// stop receiving broadcasts (throws exception if none registered)
try {
getContext().unregisterReceiver(mBroadcastReceiver);
@@ -456,26 +407,7 @@
mUserQuery = null;
mPreviousComponents = null;
}
-
- /**
- * Asks the LocationManager for location updates so that it goes and gets a fresh location
- * if needed.
- */
- private void startLocationUpdates() {
- if (mLocationManager != null && mLocationProvider != null) {
- mLocationManager.requestLocationUpdates(mLocationProvider.getName(),
- 0, 0, mDummyLocationListener, getContext().getMainLooper());
- }
- }
-
- /**
- * Makes sure to stop listening for location updates to save battery.
- */
- private void stopLocationUpdates() {
- mLocationManager.removeUpdates(mDummyLocationListener);
- }
-
/**
* Sets the search dialog to the 'working' state, which shows a working spinner in the
* right hand size of the text field.
@@ -1168,7 +1100,7 @@
*/
protected void launchQuerySearch(int actionKey, String actionMsg) {
String query = mSearchAutoComplete.getText().toString();
- Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null,
+ Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
actionKey, actionMsg);
launchIntent(intent);
}
@@ -1238,8 +1170,8 @@
// logic for falling back on the searchable default
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
- cv.put(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
- intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
+ cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
+ intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY));
// ensure the icons will work for global search
cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
@@ -1467,11 +1399,14 @@
}
Uri dataUri = (data == null) ? null : Uri.parse(data);
- String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
+ String componentName = getColumnString(
+ c, SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME);
String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
+ String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
- return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
+ return createIntent(action, dataUri, extraData, query, componentName, actionKey,
+ actionMsg);
} catch (RuntimeException e ) {
int rowNum;
try { // be really paranoid now
@@ -1490,16 +1425,17 @@
*
* @param action Intent action.
* @param data Intent data, or <code>null</code>.
- * @param query Intent query, or <code>null</code>.
* @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>.
+ * @param query Intent query, or <code>null</code>.
+ * @param componentName Data for {@link SearchManager#COMPONENT_NAME_KEY} or <code>null</code>.
* @param actionKey The key code of the action key that was pressed,
* or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
* @param actionMsg The message for the action key that was pressed,
* or <code>null</code> if none.
* @return The intent.
*/
- private Intent createIntent(String action, Uri data, String query, String extraData,
- int actionKey, String actionMsg) {
+ private Intent createIntent(String action, Uri data, String extraData, String query,
+ String componentName, int actionKey, String actionMsg) {
// Now build the Intent
Intent intent = new Intent(action);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -1512,6 +1448,9 @@
if (extraData != null) {
intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
}
+ if (componentName != null) {
+ intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName);
+ }
if (mAppSearchData != null) {
intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
}
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 1ddd20a..eb80400 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1165,6 +1165,14 @@
public final static String ACTION_KEY = "action_key";
/**
+ * Intent component name key: This key will be used for the extra populated by the
+ * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
+ *
+ * {@hide}
+ */
+ public final static String COMPONENT_NAME_KEY = "intent_component_name_key";
+
+ /**
* Intent extra data key: This key will be used for the extra populated by the
* {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
*
@@ -1364,14 +1372,24 @@
*/
public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
/**
+ * Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
+ * this element exists at the given row, this is the data that will be used when
+ * forming the suggestion's intent. If not provided, the Intent's extra data field will be null.
+ * This column allows suggestions to provide additional arbitrary data which will be included as
+ * an extra under the key EXTRA_DATA_KEY.
+ *
+ * @hide Pending API council approval.
+ */
+ public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ /**
* Column name for suggestions cursor. <i>Optional.</i> This column allows suggestions
* to provide additional arbitrary data which will be included as an extra under the key
- * {@link #EXTRA_DATA_KEY}. For use by the global search system only - if other providers
+ * {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
* attempt to use this column, the value will be overwritten by global search.
*
* @hide
*/
- public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ public final static String SUGGEST_COLUMN_INTENT_COMPONENT_NAME = "suggest_intent_component";
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, then "/" and this value will be appended to the data
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 609dd90..69c206c 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -82,9 +82,9 @@
}
}
- public int readEntityData(byte[] data, int size) throws IOException {
+ public int readEntityData(byte[] data, int offset, int size) throws IOException {
if (mHeaderReady) {
- int result = readEntityData_native(mBackupReader, data, size);
+ int result = readEntityData_native(mBackupReader, data, offset, size);
if (result >= 0) {
return result;
} else {
@@ -95,9 +95,23 @@
}
}
+ public void skipEntityData() throws IOException {
+ if (mHeaderReady) {
+ int result = skipEntityData_native(mBackupReader);
+ if (result >= 0) {
+ return;
+ } else {
+ throw new IOException("result=0x" + Integer.toHexString(result));
+ }
+ } else {
+ throw new IllegalStateException("mHeaderReady=false");
+ }
+ }
+
private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupReader);
private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
- private native int readEntityData_native(int mBackupReader, byte[] data, int size);
+ private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size);
+ private native int skipEntityData_native(int mBackupReader);
}
diff --git a/core/java/android/backup/BackupDataInputStream.java b/core/java/android/backup/BackupDataInputStream.java
new file mode 100644
index 0000000..52b1675
--- /dev/null
+++ b/core/java/android/backup/BackupDataInputStream.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/** @hide */
+public class BackupDataInputStream extends InputStream {
+
+ String key;
+ int dataSize;
+
+ BackupDataInput mData;
+ byte[] mOneByte;
+
+ BackupDataInputStream(BackupDataInput data) {
+ mData = data;
+ }
+
+ public int read() throws IOException {
+ byte[] one = mOneByte;
+ if (mOneByte == null) {
+ one = mOneByte = new byte[1];
+ }
+ mData.readEntityData(one, 0, 1);
+ return one[0];
+ }
+
+ public int read(byte[] b, int offset, int size) throws IOException {
+ return mData.readEntityData(b, offset, size);
+ }
+
+ public int read(byte[] b) throws IOException {
+ return mData.readEntityData(b, 0, b.length);
+ }
+
+ public String getKey() {
+ return this.key;
+ }
+
+ public int size() {
+ return this.dataSize;
+ }
+}
+
+
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
index ebd9906e..ee8bedd 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/RestoreHelper.java
@@ -16,8 +16,16 @@
package android.backup;
+import java.io.InputStream;
+
/** @hide */
public interface RestoreHelper {
- public void performRestore();
+ /**
+ * Called by RestoreHelperDispatcher to dispatch one entity of data.
+ * <p class=note>
+ * Do not close the <code>data</code> stream. Do not read more than
+ * <code>dataSize</code> bytes from <code>data</code>.
+ */
+ public void performRestore(BackupDataInputStream data);
}
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
new file mode 100644
index 0000000..cbfefdc
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperDispatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/** @hide */
+public class RestoreHelperDispatcher {
+ HashMap<String,RestoreHelper> mHelpers;
+
+ public void addHelper(String keyPrefix, RestoreHelper helper) {
+ mHelpers.put(keyPrefix, helper);
+ }
+
+ public void dispatch(BackupDataInput input) throws IOException {
+ BackupDataInputStream stream = new BackupDataInputStream(input);
+ while (input.readNextHeader()) {
+ String rawKey = input.getKey();
+ int pos = rawKey.indexOf(':');
+ if (pos > 0) {
+ String prefix = rawKey.substring(0, pos);
+ RestoreHelper helper = mHelpers.get(prefix);
+ if (helper != null) {
+ stream.dataSize = input.getDataSize();
+ stream.key = rawKey.substring(pos+1);
+ helper.performRestore(stream);
+ }
+ }
+ input.skipEntityData(); // In case they didn't consume the data.
+ }
+ }
+}
diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/backup/RestoreHelperDistributor.java
deleted file mode 100644
index 555ca79..0000000
--- a/core/java/android/backup/RestoreHelperDistributor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.backup;
-
-import java.util.HashMap;
-
-/** @hide */
-public class RestoreHelperDistributor {
- HashMap<String,RestoreHelper> mHelpers;
-
- public void addHelper(String keyPrefix, RestoreHelper helper) {
- mHelpers.put(keyPrefix, helper);
- }
-}
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 14323b8..5bfdcc4 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -84,7 +84,7 @@
private final Rect mInvalidRect = new Rect();
private final Path mPath = new Path();
- private boolean mGestureVisible;
+ private boolean mGestureVisible = true;
private float mX;
private float mY;
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
index 739a8e4..02211fd 100755
--- a/core/java/android/speech/tts/ITts.aidl
+++ b/core/java/android/speech/tts/ITts.aidl
@@ -39,7 +39,7 @@
void addSpeechFile(in String text, in String filename);
- void setLanguage(in String language);
+ void setLanguage(in String language, in String country, in String variant);
boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 2c0c09e..8f58194 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -22,13 +22,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.HashMap;
+import java.util.Locale;
/**
*
@@ -36,7 +35,7 @@
*
* {@hide}
*/
-//TODO #TTS# review + complete javadoc
+//TODO #TTS# review + complete javadoc + add links to constants
public class TextToSpeech {
/**
@@ -52,9 +51,18 @@
*/
public static final int TTS_ERROR_MISSING_RESOURCE = -2;
+ /**
+ * Queue mode where all entries in the playback queue (media to be played
+ * and text to be synthesized) are dropped and replaced by the new entry.
+ */
+ public static final int TTS_QUEUE_FLUSH = 0;
+ /**
+ * Queue mode where the new entry is added at the end of the playback queue.
+ */
+ public static final int TTS_QUEUE_ADD = 1;
/**
- * Called when the TTS has initialized
+ * Called when the TTS has initialized.
*
* The InitListener must implement the onInit function. onInit is passed a
* status code indicating the result of the TTS initialization.
@@ -73,9 +81,9 @@
}
/**
- * Connection needed for the TTS
+ * Connection needed for the TTS.
*/
- private ServiceConnection serviceConnection;
+ private ServiceConnection mServiceConnection;
private ITts mITts = null;
private Context mContext = null;
@@ -104,8 +112,7 @@
}
- public void setOnSpeechCompletedListener(
- final OnSpeechCompletedListener listener) {
+ public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) {
synchronized(mSpeechCompListenerLock) {
mSpeechCompListener = listener;
}
@@ -126,7 +133,7 @@
mStarted = false;
// Initialize the TTS, run the callback after the binding is successful
- serviceConnection = new ServiceConnection() {
+ mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized(mStartLock) {
mITts = ITts.Stub.asInterface(service);
@@ -176,7 +183,7 @@
Intent intent = new Intent("android.intent.action.USE_TTS");
intent.addCategory("android.intent.category.TTS");
- mContext.bindService(intent, serviceConnection,
+ mContext.bindService(intent, mServiceConnection,
Context.BIND_AUTO_CREATE);
// TODO handle case where the binding works (should always work) but
// the plugin fails
@@ -190,7 +197,7 @@
*/
public void shutdown() {
try {
- mContext.unbindService(serviceConnection);
+ mContext.unbindService(mServiceConnection);
} catch (IllegalArgumentException e) {
// Do nothing and fail silently since an error here indicates that
// binding never succeeded in the first place.
@@ -291,8 +298,8 @@
* @param text
* The string of text to be spoken.
* @param queueMode
- * The queuing strategy to use. Use 0 for no queuing, and 1 for
- * queuing.
+ * The queuing strategy to use.
+ * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* @param params
* The hashmap of speech parameters to be used.
*/
@@ -329,12 +336,11 @@
* @param earcon
* The earcon that should be played
* @param queueMode
- * 0 for no queue (interrupts all previous utterances), 1 for
- * queued
+ * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
* @param params
* The hashmap of parameters to be used.
*/
- public void playEarcon(String earcon, int queueMode,
+ public void playEarcon(String earcon, int queueMode,
HashMap<String,String> params) {
synchronized (mStartLock) {
if (!mStarted) {
@@ -358,8 +364,8 @@
}
}
}
-
-
+
+
public void playSilence(long durationInMs, int queueMode) {
// TODO implement, already present in TTS service
}
@@ -429,20 +435,22 @@
* Note that the speech rate is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified
* speech rate, but there is no guarantee.
- *
- * Currently, this will change the speech rate for the espeak engine, but it
- * has no effect on any pre-recorded speech.
+ * This has no effect on any pre-recorded speech.
*
* @param speechRate
- * The speech rate for the TTS engine.
+ * The speech rate for the TTS engine. 1 is the normal speed,
+ * lower values slow down the speech (0.5 is half the normal speech rate),
+ * greater values accelerate it (2 is twice the normal speech rate).
*/
- public void setSpeechRate(int speechRate) {
+ public void setSpeechRate(float speechRate) {
synchronized (mStartLock) {
if (!mStarted) {
return;
}
try {
- mITts.setSpeechRate(speechRate);
+ if (speechRate > 0) {
+ mITts.setSpeechRate((int)(speechRate*100));
+ }
} catch (RemoteException e) {
// TTS died; restart it.
mStarted = false;
@@ -457,24 +465,18 @@
*
* Note that the language is not universally supported by all engines and
* will be treated as a hint. The TTS library will try to use the specified
- * language, but there is no guarantee.
+ * language as represented by the Locale, but there is no guarantee.
*
- * Currently, this will change the language for the espeak engine, but it
- * has no effect on any pre-recorded speech.
- *
- * @param language
- * The language to be used. The languages are specified by their
- * IETF language tags as defined by BCP 47. This is the same
- * standard used for the lang attribute in HTML. See:
- * http://en.wikipedia.org/wiki/IETF_language_tag
+ * @param loc
+ * The locale describing the language to be used.
*/
- public void setLanguage(String language) {
+ public void setLanguage(Locale loc) {
synchronized (mStartLock) {
if (!mStarted) {
return;
}
try {
- mITts.setLanguage(language);
+ mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant());
} catch (RemoteException e) {
// TTS died; restart it.
mStarted = false;
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 9daabca..84ed729 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -42,11 +42,14 @@
*/
/**
* Verify that this is a suitable time for a backup pass. This should return zero
- * if a backup is reasonable right now, false otherwise. This method will be called
- * outside of the {@link #startSession}/{@link #endSession} pair.
+ * if a backup is reasonable right now, some positive value otherwise. This method
+ * will be called outside of the {@link #startSession}/{@link #endSession} pair.
*
- * <p>If this is not a suitable time for a backup, the transport should suggest a
+ * <p>If this is not a suitable time for a backup, the transport should return a
* backoff delay, in milliseconds, after which the Backup Manager should try again.
+ *
+ * @return Zero if this is a suitable time for a backup pass, or a positive time delay
+ * in milliseconds to suggest deferring the backup pass for a while.
*/
long requestBackupTime();
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 5da0883..123c072 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -84,7 +84,7 @@
bufSize = dataSize;
buf = new byte[bufSize];
}
- changeSet.readEntityData(buf, dataSize);
+ changeSet.readEntityData(buf, 0, dataSize);
if (DEBUG) Log.v(TAG, " + data size " + dataSize);
File entityFile = new File(packageDir, key);
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 5b2fb73..cf8a8e8 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -55,18 +55,13 @@
readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
{
int err;
+ bool done;
BackupDataReader* reader = (BackupDataReader*)r;
- err = reader->Status();
- if (err != 0) {
- return err < 0 ? err : -1;
- }
-
int type = 0;
- err = reader->ReadNextHeader(&type);
- if (err == EIO) {
- // Clean EOF with no footer block; just claim we're done
+ err = reader->ReadNextHeader(&done, &type);
+ if (done) {
return 1;
}
@@ -75,24 +70,12 @@
}
switch (type) {
- case BACKUP_HEADER_APP_V1:
- {
- String8 packageName;
- int cookie;
- err = reader->ReadAppHeader(&packageName, &cookie);
- if (err != 0) {
- LOGD("ReadAppHeader() returned %d; aborting", err);
- return err < 0 ? err : -1;
- }
- break;
- }
case BACKUP_HEADER_ENTITY_V1:
{
String8 key;
size_t dataSize;
err = reader->ReadEntityHeader(&key, &dataSize);
if (err != 0) {
- LOGD("ReadEntityHeader(); aborting", err);
return err < 0 ? err : -1;
}
// TODO: Set the fields in the entity object
@@ -101,10 +84,6 @@
env->SetIntField(entity, s_dataSizeField, dataSize);
return 0;
}
- case BACKUP_FOOTER_APP_V1:
- {
- break;
- }
default:
LOGD("Unknown header type: 0x%08x\n", type);
return -1;
@@ -115,12 +94,12 @@
}
static jint
-readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
+readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int offset, int size)
{
int err;
BackupDataReader* reader = (BackupDataReader*)r;
- if (env->GetArrayLength(data) < size) {
+ if (env->GetArrayLength(data) < (size+offset)) {
// size mismatch
return -1;
}
@@ -130,19 +109,31 @@
return -2;
}
- err = reader->ReadEntityData(dataBytes, size);
+ err = reader->ReadEntityData(dataBytes+offset, size);
env->ReleaseByteArrayElements(data, dataBytes, 0);
return err;
}
+static jint
+skipEntityData_native(JNIEnv* env, jobject clazz, int r)
+{
+ int err;
+ BackupDataReader* reader = (BackupDataReader*)r;
+
+ err = reader->SkipEntityData();
+
+ return err;
+}
+
static const JNINativeMethod g_methods[] = {
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
{ "dtor", "(I)V", (void*)dtor_native },
{ "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
(void*)readNextHeader_native },
- { "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
+ { "readEntityData_native", "(I[BII)I", (void*)readEntityData_native },
+ { "skipEntityData_native", "(I)I", (void*)skipEntityData_native },
};
int register_android_backup_BackupDataInput(JNIEnv* env)
diff --git a/core/res/res/layout/recent_apps_dialog.xml b/core/res/res/layout/recent_apps_dialog.xml
index 852b2f1..c4ee95d 100644
--- a/core/res/res/layout/recent_apps_dialog.xml
+++ b/core/res/res/layout/recent_apps_dialog.xml
@@ -17,67 +17,63 @@
*/
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
+ android:layout_height="wrap_content"
+ android:padding="3dip"
+ android:orientation="vertical">
+
+ <!-- This is only intended to be visible when all buttons (below) are invisible -->
+ <TextView
+ android:id="@+id/no_applications_message"
+ android:layout_width="285dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="15dip"
+ android:layout_marginBottom="15dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="@android:string/no_recent_tasks" />
+
+ <!-- The first row has a fixed-width because the UI spec requires the box
+ to display with full-width no matter how many icons are visible, but to
+ adjust height based on number of rows. -->
+ <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
+ <LinearLayout
+ android:layout_width="285dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button1" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button2" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button3" />
+
+ </LinearLayout>
+
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="3dip"
- android:orientation="vertical">
-
- <!-- This is only intended to be visible when all buttons (below) are invisible -->
- <TextView
- android:id="@+id/no_applications_message"
- android:layout_width="285dip"
- android:layout_height="wrap_content"
- android:layout_marginTop="15dip"
- android:layout_marginBottom="15dip"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@android:string/no_recent_tasks" />
-
- <!-- The first row has a fixed-width because the UI spec requires the box
- to display with full-width no matter how many icons are visible, but to
- adjust height based on number of rows. -->
- <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
- <LinearLayout
- android:layout_width="285dip"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
+ android:orientation="horizontal" >
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button1" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button2" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button3" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal" >
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button4" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button5" />
-
- <include
- layout="@android:layout/recent_apps_icon"
- android:id="@+id/button6" />
-
- </LinearLayout>
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button4" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button5" />
+
+ <include
+ layout="@android:layout/recent_apps_icon"
+ android:id="@+id/button6" />
+
</LinearLayout>
-</FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/recent_apps_icon.xml b/core/res/res/layout/recent_apps_icon.xml
index b8cf089..d32643c 100644
--- a/core/res/res/layout/recent_apps_icon.xml
+++ b/core/res/res/layout/recent_apps_icon.xml
@@ -18,27 +18,22 @@
-->
<!-- This is not a standalone element - it is imported into recent_apps_dialog.xml -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="87dip"
- android:layout_height="78dip"
- android:layout_margin="3dip"
- android:orientation="vertical"
- android:gravity="center_vertical"
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/label"
style="?android:attr/buttonStyle"
- android:background="@drawable/btn_application_selector">
- <ImageView android:id="@+id/icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_gravity="center_horizontal"
- android:scaleType="fitCenter" />
- <TextView android:id="@+id/label"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="12dip"
- android:maxLines="1"
- android:ellipsize="end"
- android:duplicateParentState="true"
- android:textColor="@color/primary_text_dark_focused"
- android:gravity="center_horizontal" />
-</LinearLayout>
+ android:background="@drawable/btn_application_selector"
+ android:layout_width="87dip"
+ android:layout_height="88dip"
+ android:layout_margin="3dip"
+ android:textColor="@color/primary_text_dark_focused"
+
+ android:paddingTop="5dip"
+ android:paddingBottom="2dip"
+ android:drawablePadding="0dip"
+
+ android:textSize="13dip"
+ android:maxLines="2"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:gravity="top|center_horizontal" />
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index f60f4ea..3ca8ad2 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -23,30 +23,15 @@
namespace android {
enum {
- BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian)
BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
- BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian)
};
-// the sizes of all of these match.
-typedef struct {
- int type; // == BACKUP_HEADER_APP_V1
- int packageLen; // length of the name of the package that follows, not including the null.
- int cookie;
-} app_header_v1;
-
typedef struct {
int type; // BACKUP_HEADER_ENTITY_V1
int keyLen; // length of the key name, not including the null terminator
int dataSize; // size of the data, not including the padding, -1 means delete
} entity_header_v1;
-typedef struct {
- int type; // BACKUP_FOOTER_APP_V1
- int entityCount; // the number of entities that were written
- int cookie;
-} app_footer_v1;
-
/**
* Writes the data.
@@ -61,13 +46,9 @@
// does not close fd
~BackupDataWriter();
- status_t WriteAppHeader(const String8& packageName, int cookie);
-
status_t WriteEntityHeader(const String8& key, size_t dataSize);
status_t WriteEntityData(const void* data, size_t size);
- status_t WriteAppFooter(int cookie);
-
private:
explicit BackupDataWriter();
status_t write_padding_for(int n);
@@ -92,28 +73,26 @@
~BackupDataReader();
status_t Status();
- status_t ReadNextHeader(int* type = NULL);
+ status_t ReadNextHeader(bool* done, int* type);
- status_t ReadAppHeader(String8* packageName, int* cookie);
bool HasEntities();
status_t ReadEntityHeader(String8* key, size_t* dataSize);
status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
status_t ReadEntityData(void* data, size_t size);
- status_t ReadAppFooter(int* cookie);
private:
explicit BackupDataReader();
status_t skip_padding();
int m_fd;
+ bool m_done;
status_t m_status;
ssize_t m_pos;
+ ssize_t m_dataEndPos;
int m_entityCount;
union {
int type;
- app_header_v1 app;
entity_header_v1 entity;
- app_footer_v1 footer;
} m_header;
};
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index 71c1cf4..ce3fa88 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -30,6 +30,7 @@
return new FileKeystore();
}
+ // for compatiblity, start from here
/**
*/
public abstract String getUserkey(String key);
@@ -46,6 +47,34 @@
*/
public abstract String[] getAllUserkeyKeys();
+ // to here
+
+ /**
+ */
+ public abstract String getCaCertificate(String key);
+
+ /**
+ */
+ public abstract String getUserCertificate(String key);
+
+ /**
+ */
+ public abstract String getUserPrivateKey(String key);
+
+ /**
+ * Returns the array of the certificate keynames in keystore if successful.
+ * Or return an empty array if error.
+ *
+ * @return array of the certificate keynames
+ */
+ public abstract String[] getAllUserCertificateKeys();
+
+ /**
+ */
+ public abstract String[] getAllCaCertificateKeys();
+
+ /**
+ */
public abstract String[] getSupportedKeyStrenghs();
/**
@@ -63,13 +92,25 @@
private static class FileKeystore extends Keystore {
private static final String SERVICE_NAME = "keystore";
+ private static final String LIST_CA_CERTIFICATES = "listcacerts";
+ private static final String LIST_USER_CERTIFICATES = "listusercerts";
+ private static final String GET_CA_CERTIFICATE = "getcacert";
+ private static final String GET_USER_CERTIFICATE = "getusercert";
+ private static final String GET_USER_KEY = "getuserkey";
+ private static final String ADD_CA_CERTIFICATE = "addcacert";
+ private static final String ADD_USER_CERTIFICATE = "addusercert";
+ private static final String ADD_USER_KEY = "adduserkey";
+ private static final String COMMAND_DELIMITER = "\t";
+ private static final ServiceCommand mServiceCommand =
+ new ServiceCommand(SERVICE_NAME);
+
+ // for compatiblity, start from here
+
private static final String LIST_CERTIFICATES = "listcerts";
private static final String LIST_USERKEYS = "listuserkeys";
private static final String PATH = "/data/misc/keystore/";
private static final String USERKEY_PATH = PATH + "userkeys/";
private static final String CERT_PATH = PATH + "certs/";
- private static final ServiceCommand mServiceCommand =
- new ServiceCommand(SERVICE_NAME);
@Override
public String getUserkey(String key) {
@@ -81,12 +122,6 @@
return CERT_PATH + key;
}
- /**
- * Returns the array of the certificate names in keystore if successful.
- * Or return an empty array if error.
- *
- * @return array of the certificates
- */
@Override
public String[] getAllCertificateKeys() {
try {
@@ -98,12 +133,6 @@
}
}
- /**
- * Returns the array of the names of private keys in keystore if successful.
- * Or return an empty array if errors.
- *
- * @return array of the user keys
- */
@Override
public String[] getAllUserkeyKeys() {
try {
@@ -115,6 +144,48 @@
}
}
+ // to here
+
+ @Override
+ public String getUserPrivateKey(String key) {
+ return mServiceCommand.execute(
+ GET_USER_KEY + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String getUserCertificate(String key) {
+ return mServiceCommand.execute(
+ GET_USER_CERTIFICATE + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String getCaCertificate(String key) {
+ return mServiceCommand.execute(
+ GET_CA_CERTIFICATE + COMMAND_DELIMITER + key);
+ }
+
+ @Override
+ public String[] getAllUserCertificateKeys() {
+ try {
+ String result = mServiceCommand.execute(LIST_USER_CERTIFICATES);
+ if (result != null) return result.split("\\s+");
+ return NOTFOUND;
+ } catch (NumberFormatException ex) {
+ return NOTFOUND;
+ }
+ }
+
+ @Override
+ public String[] getAllCaCertificateKeys() {
+ try {
+ String result = mServiceCommand.execute(LIST_CA_CERTIFICATES);
+ if (result != null) return result.split("\\s+");
+ return NOTFOUND;
+ } catch (NumberFormatException ex) {
+ return NOTFOUND;
+ }
+ }
+
@Override
public String[] getSupportedKeyStrenghs() {
// TODO: real implementation
@@ -149,5 +220,26 @@
public void addCertificate(String cert) {
// TODO: real implementation
}
+
+ private boolean addUserCertificate(String key, String certificate,
+ String privateKey) {
+ if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + certificate) != null) {
+ if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + privateKey) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean addCaCertificate(String key, String content) {
+ if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER
+ + key + COMMAND_DELIMITER + content) != null) {
+ return true;
+ }
+ return false;
+ }
+
}
}
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 8c9f875..16ff1e5 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -86,46 +86,6 @@
}
status_t
-BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- ssize_t amt;
-
- amt = write_padding_for(m_pos);
- if (amt != 0) {
- return amt;
- }
-
- app_header_v1 header;
- ssize_t nameLen;
-
- nameLen = packageName.length();
-
- header.type = tolel(BACKUP_HEADER_APP_V1);
- header.packageLen = tolel(nameLen);
- header.cookie = cookie;
-
- amt = write(m_fd, &header, sizeof(app_header_v1));
- if (amt != sizeof(app_header_v1)) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- amt = write(m_fd, packageName.string(), nameLen+1);
- if (amt != nameLen+1) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- return NO_ERROR;
-}
-
-status_t
BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
{
if (m_status != NO_ERROR) {
@@ -188,40 +148,11 @@
return NO_ERROR;
}
-status_t
-BackupDataWriter::WriteAppFooter(int cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
-
- ssize_t amt;
-
- amt = write_padding_for(m_pos);
- if (amt != 0) {
- return amt;
- }
-
- app_footer_v1 footer;
- ssize_t nameLen;
-
- footer.type = tolel(BACKUP_FOOTER_APP_V1);
- footer.entityCount = tolel(m_entityCount);
- footer.cookie = cookie;
-
- amt = write(m_fd, &footer, sizeof(app_footer_v1));
- if (amt != sizeof(app_footer_v1)) {
- m_status = errno;
- return m_status;
- }
- m_pos += amt;
-
- return NO_ERROR;
-}
BackupDataReader::BackupDataReader(int fd)
:m_fd(fd),
+ m_done(false),
m_status(NO_ERROR),
m_pos(0),
m_entityCount(0)
@@ -260,31 +191,25 @@
} while(0)
status_t
-BackupDataReader::ReadNextHeader(int* type)
+BackupDataReader::ReadNextHeader(bool* done, int* type)
{
+ *done = m_done;
if (m_status != NO_ERROR) {
return m_status;
}
int amt;
- SKIP_PADDING();
+ // No error checking here, in case we're at the end of the stream. Just let read() fail.
+ skip_padding();
amt = read(m_fd, &m_header, sizeof(m_header));
+ *done = m_done = (amt == 0);
CHECK_SIZE(amt, sizeof(m_header));
// validate and fix up the fields.
m_header.type = fromlel(m_header.type);
switch (m_header.type)
{
- case BACKUP_HEADER_APP_V1:
- m_header.app.packageLen = fromlel(m_header.app.packageLen);
- if (m_header.app.packageLen < 0) {
- LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
- (int)m_header.app.packageLen);
- m_status = EINVAL;
- }
- m_header.app.cookie = m_header.app.cookie;
- break;
case BACKUP_HEADER_ENTITY_V1:
m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
if (m_header.entity.keyLen <= 0) {
@@ -295,15 +220,6 @@
m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
m_entityCount++;
break;
- case BACKUP_FOOTER_APP_V1:
- m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
- if (m_header.footer.entityCount < 0) {
- LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
- (int)m_header.footer.entityCount);
- m_status = EINVAL;
- }
- m_header.footer.cookie = m_header.footer.cookie;
- break;
default:
LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
m_status = EINVAL;
@@ -316,30 +232,6 @@
return m_status;
}
-status_t
-BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
- if (m_header.type != BACKUP_HEADER_APP_V1) {
- return EINVAL;
- }
- size_t size = m_header.app.packageLen;
- char* buf = packageName->lockBuffer(size);
- if (buf == NULL) {
- packageName->unlockBuffer();
- m_status = ENOMEM;
- return m_status;
- }
- int amt = read(m_fd, buf, size+1);
- CHECK_SIZE(amt, (int)size+1);
- packageName->unlockBuffer(size);
- m_pos += size+1;
- *cookie = m_header.app.cookie;
- return NO_ERROR;
-}
-
bool
BackupDataReader::HasEntities()
{
@@ -368,6 +260,7 @@
m_pos += size+1;
*dataSize = m_header.entity.dataSize;
SKIP_PADDING();
+ m_dataEndPos = m_pos + *dataSize;
return NO_ERROR;
}
@@ -381,7 +274,7 @@
return EINVAL;
}
if (m_header.entity.dataSize > 0) {
- int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
+ int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
return pos == -1 ? (int)errno : (int)NO_ERROR;
} else {
return NO_ERROR;
@@ -394,6 +287,15 @@
if (m_status != NO_ERROR) {
return m_status;
}
+ int remaining = m_dataEndPos - m_pos;
+ if (size > remaining) {
+ printf("size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+ size, m_pos, m_dataEndPos, remaining);
+ size = remaining;
+ }
+ if (remaining <= 0) {
+ return 0;
+ }
int amt = read(m_fd, data, size);
CHECK_SIZE(amt, (int)size);
m_pos += size;
@@ -401,25 +303,6 @@
}
status_t
-BackupDataReader::ReadAppFooter(int* cookie)
-{
- if (m_status != NO_ERROR) {
- return m_status;
- }
- if (m_header.type != BACKUP_FOOTER_APP_V1) {
- return EINVAL;
- }
- if (m_header.footer.entityCount != m_entityCount) {
- LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
- m_header.footer.entityCount);
- m_status = EINVAL;
- return m_status;
- }
- *cookie = m_header.footer.cookie;
- return NO_ERROR;
-}
-
-status_t
BackupDataReader::skip_padding()
{
ssize_t amt;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 4c3e37d..c1d5404 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -689,41 +689,27 @@
// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
const unsigned char DATA_GOLDEN_FILE[] = {
- 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
- 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
- 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
- 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
- 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
+ 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+ 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
- 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
- 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
- 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
- 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
- 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
- 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+ 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
- 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
- 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
- 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
- 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+ 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
- 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
- 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
- 0x99, 0x99, 0x77, 0x77
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
};
const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
@@ -733,12 +719,6 @@
int err;
String8 text(str);
- err = writer.WriteAppHeader(text, 0xaabbccdd);
- if (err != 0) {
- fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
- return err;
- }
-
err = writer.WriteEntityHeader(text, text.length()+1);
if (err != 0) {
fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
@@ -779,8 +759,6 @@
err |= test_write_header_and_entity(writer, "padded_to_2__");
err |= test_write_header_and_entity(writer, "padded_to1");
- writer.WriteAppFooter(0x77779999);
-
close(fd);
err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
@@ -800,70 +778,59 @@
String8 string;
int cookie = 0x11111111;
size_t actualSize;
+ bool done;
+ int type;
// printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
- err = reader.ReadNextHeader();
+ err = reader.ReadNextHeader(&done, &type);
+ if (done) {
+ fprintf(stderr, "should not be done yet\n");
+ goto finished;
+ }
if (err != 0) {
fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
- goto done;
+ goto finished;
}
-
- err = reader.ReadAppHeader(&string, &cookie);
- if (err != 0) {
- fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
- goto done;
- }
- if (string != str) {
- fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
+ if (type != BACKUP_HEADER_ENTITY_V1) {
err = EINVAL;
- goto done;
- }
- if (cookie != (int)0xaabbccdd) {
- fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
- err = EINVAL;
- goto done;
- }
-
- err = reader.ReadNextHeader();
- if (err != 0) {
- fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
- goto done;
+ fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
}
err = reader.ReadEntityHeader(&string, &actualSize);
if (err != 0) {
fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
- goto done;
+ goto finished;
}
if (string != str) {
fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
err = EINVAL;
- goto done;
+ goto finished;
}
if ((int)actualSize != bufSize) {
fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
actualSize);
err = EINVAL;
- goto done;
+ goto finished;
}
err = reader.ReadEntityData(buf, bufSize);
if (err != NO_ERROR) {
fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
- goto done;
+ goto finished;
}
if (0 != memcmp(buf, str, bufSize)) {
fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
- "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
+ "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+ buf[0], buf[1], buf[2], buf[3]);
err = EINVAL;
- goto done;
+ goto finished;
}
// The next read will confirm whether it got the right amount of data.
-done:
+finished:
if (err != NO_ERROR) {
fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
}
@@ -923,23 +890,6 @@
if (err == NO_ERROR) {
err = test_read_header_and_entity(reader, "padded_to1");
}
-
- if (err == NO_ERROR) {
- err = reader.ReadNextHeader();
- if (err != 0) {
- fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
- }
-
- if (err == NO_ERROR) {
- int cookie;
- err |= reader.ReadAppFooter(&cookie);
- if (cookie != 0x77779999) {
- fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
- 0x77779999, cookie);
- err = EINVAL;
- }
- }
- }
}
close(fd);
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index dfecfd8..54d038a 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -269,10 +269,10 @@
}
}
-// TODO update to use language, country, variant
+
static void
android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language)
+ jstring language, jstring country, jstring variant)
{
if (jniData == 0) {
LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
@@ -281,14 +281,16 @@
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
const char *langNativeString = env->GetStringUTFChars(language, 0);
+ const char *countryNativeString = env->GetStringUTFChars(country, 0);
+ const char *variantNativeString = env->GetStringUTFChars(variant, 0);
// TODO check return codes
if (pSynthData->mNativeSynthInterface) {
- // TODO update to use language, country, variant
- // commented out to not break the build
- //pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
- // strlen(langNativeString));
+ pSynthData->mNativeSynthInterface->setLanguage(langNativeString, countryNativeString,
+ variantNativeString);
}
env->ReleaseStringUTFChars(language, langNativeString);
+ env->ReleaseStringUTFChars(language, countryNativeString);
+ env->ReleaseStringUTFChars(language, variantNativeString);
}
@@ -496,6 +498,7 @@
return env->NewStringUTF(buf);
}
+
JNIEXPORT int JNICALL
android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
{
@@ -531,7 +534,7 @@
(void*)android_tts_SynthProxy_synthesizeToFile
},
{ "native_setLanguage",
- "(ILjava/lang/String;)V",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
(void*)android_tts_SynthProxy_setLanguage
},
{ "native_setSpeechRate",
@@ -567,7 +570,6 @@
#define SP_JNIDATA_FIELD_NAME "mJniData"
#define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
-// TODO: verify this is the correct path
static const char* const kClassPathName = "android/tts/SynthProxy";
jint JNI_OnLoad(JavaVM* vm, void* reserved)
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index e065f40..364dc58 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -70,8 +70,8 @@
/**
* Sets the language
*/
- public void setLanguage(String language) {
- native_setLanguage(mJniData, language);
+ public void setLanguage(String language, String country, String variant) {
+ native_setLanguage(mJniData, language, country, variant);
}
/**
@@ -141,7 +141,8 @@
private native final void native_synthesizeToFile(int jniData, String text, String filename);
- private native final void native_setLanguage(int jniData, String language);
+ private native final void native_setLanguage(int jniData, String language, String country,
+ String variant);
private native final void native_setSpeechRate(int jniData, int speechRate);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 8a64113..f7dd0e8 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -129,7 +129,9 @@
mSpeechQueue = new ArrayList<SpeechItem>();
mPlayer = null;
- setLanguage(prefs.getString("lang_pref", "en-rUS"));
+ // TODO set default settings
+ //setLanguage(prefs.getString("lang_pref", "en-rUS"));
+ setLanguage("eng", "USA", "");
setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140")));
}
@@ -155,7 +157,7 @@
nativeSynth.setSpeechRate(rate);
}
- private void setLanguage(String lang) {
+ private void setLanguage(String lang, String country, String variant) {
if (prefs.getBoolean("override_pref", false)) {
// This is set to the default here so that the preview in the prefs
// activity will show the change without a restart, even if apps are
@@ -163,7 +165,8 @@
// allowed to change the defaults.
lang = prefs.getString("lang_pref", "en-rUS");
}
- nativeSynth.setLanguage(lang);
+ Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
+ nativeSynth.setLanguage(lang, country, variant);
}
/**
@@ -683,20 +686,14 @@
}
/**
- * Sets the speech rate for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
+ * Sets the speech rate for the TTS, which affects the synthesized voice.
*
- * @param language
- * Language values are based on the Android conventions for
- * localization as described in the Android platform
- * documentation on internationalization. This implies that
- * language data is specified in the format xx-rYY, where xx
- * is a two letter ISO 639-1 language code in lowercase and
- * rYY is a two letter ISO 3166-1-alpha-2 language code in
- * uppercase preceded by a lowercase "r".
+ * @param lang the three letter ISO language code.
+ * @param country the three letter ISO country code.
+ * @param variant the variant code associated with the country and language pair.
*/
- public void setLanguage(String language) {
- mSelf.setLanguage(language);
+ public void setLanguage(String lang, String country, String variant) {
+ mSelf.setLanguage(lang, country, variant);
}
/**
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index ce56921..8358c5c 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -50,16 +50,17 @@
}
private String getCaCertPath() {
- return Keystore.getInstance().getCertificate(
+ return Keystore.getInstance().getCaCertificate(
getProfile().getCaCertificate());
}
private String getUserCertPath() {
- return Keystore.getInstance().getCertificate(
+ return Keystore.getInstance().getUserCertificate(
getProfile().getUserCertificate());
}
private String getUserkeyPath() {
- return Keystore.getInstance().getUserkey(getProfile().getUserkey());
+ return Keystore.getInstance().getUserPrivateKey(
+ getProfile().getUserCertificate());
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4742636..d842d34 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -68,7 +68,7 @@
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
private static final boolean DEBUG = true;
-
+
private static final long COLLECTION_INTERVAL = 1000;
//private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
@@ -90,7 +90,7 @@
private class BackupRequest {
public ApplicationInfo appInfo;
public boolean fullBackup;
-
+
BackupRequest(ApplicationInfo app, boolean isFull) {
appInfo = app;
fullBackup = isFull;
@@ -120,7 +120,9 @@
private final Object mClearDataLock = new Object();
private volatile boolean mClearingData;
+ // Current active transport & restore session
private int mTransportId;
+ private IBackupTransport mTransport;
private RestoreSession mActiveRestoreSession;
private File mStateDir;
@@ -128,7 +130,7 @@
private File mJournalDir;
private File mJournal;
private RandomAccessFile mJournalStream;
-
+
public BackupManagerService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
@@ -144,14 +146,16 @@
mJournalDir.mkdirs();
makeJournalLocked(); // okay because no other threads are running yet
- //!!! TODO: default to cloud transport, not local
- mTransportId = BackupManager.TRANSPORT_LOCAL;
-
// Build our mapping of uid to backup client services
synchronized (mBackupParticipants) {
addPackageParticipantsLocked(null);
}
+ // Stand up our default transport
+ //!!! TODO: default to cloud transport, not local
+ mTransportId = BackupManager.TRANSPORT_LOCAL;
+ mTransport = createTransport(mTransportId);
+
// Now that we know about valid backup participants, parse any
// leftover journal files and schedule a new backup pass
parseLeftoverJournals();
@@ -284,7 +288,7 @@
// deleted. If we crash prior to that, the old journal is parsed
// at next boot and the journaled requests fulfilled.
}
- (new PerformBackupThread(mTransportId, mBackupQueue, oldJournal)).run();
+ (new PerformBackupThread(mTransport, mBackupQueue, oldJournal)).run();
break;
case MSG_RUN_FULL_BACKUP:
@@ -396,7 +400,7 @@
}
return allApps;
}
-
+
// Reset the given package's known backup participants. Unlike add/remove, the update
// action cannot be passed a null package name.
void updatePackageParticipantsLocked(String packageName) {
@@ -505,13 +509,13 @@
class PerformBackupThread extends Thread {
private static final String TAG = "PerformBackupThread";
- int mTransport;
+ IBackupTransport mTransport;
ArrayList<BackupRequest> mQueue;
File mJournal;
- public PerformBackupThread(int transportId, ArrayList<BackupRequest> queue,
+ public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
File journal) {
- mTransport = transportId;
+ mTransport = transport;
mQueue = queue;
mJournal = journal;
}
@@ -520,15 +524,9 @@
public void run() {
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
- // stand up the current transport
- IBackupTransport transport = createTransport(mTransport);
- if (transport == null) {
- return;
- }
-
// start up the transport
try {
- transport.startSession();
+ mTransport.startSession();
} catch (Exception e) {
Log.e(TAG, "Error session transport");
e.printStackTrace();
@@ -536,11 +534,11 @@
}
// The transport is up and running; now run all the backups in our queue
- doQueuedBackups(transport);
+ doQueuedBackups(mTransport);
// Finally, tear down the transport
try {
- transport.endSession();
+ mTransport.endSession();
} catch (Exception e) {
Log.e(TAG, "Error ending transport");
e.printStackTrace();
@@ -850,8 +848,26 @@
// a backup pass for each of them.
Log.d(TAG, "dataChanged packageName=" + packageName);
-
- HashSet<ApplicationInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
+
+ // If the caller does not hold the BACKUP permission, it can only request a
+ // backup of its own data.
+ HashSet<ApplicationInfo> targets;
+ if ((mContext.checkPermission("android.permission.BACKUP", Binder.getCallingPid(),
+ Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+ targets = mBackupParticipants.get(Binder.getCallingUid());
+ } else {
+ // a caller with full permission can ask to back up any participating app
+ // !!! TODO: allow backup of ANY app?
+ if (DEBUG) Log.v(TAG, "Privileged caller, allowing backup of other apps");
+ targets = new HashSet<ApplicationInfo>();
+ int N = mBackupParticipants.size();
+ for (int i = 0; i < N; i++) {
+ HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+ if (s != null) {
+ targets.addAll(s);
+ }
+ }
+ }
if (targets != null) {
synchronized (mQueueLock) {
// Note that this client has made data changes that need to be backed up
@@ -921,8 +937,14 @@
public int selectBackupTransport(int transportId) {
mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
- int prevTransport = mTransportId;
- mTransportId = transportId;
+ int prevTransport = -1;
+ IBackupTransport newTransport = createTransport(transportId);
+ if (newTransport != null) {
+ // !!! TODO: a method on the old transport that says it's being deactivated?
+ mTransport = newTransport;
+ prevTransport = mTransportId;
+ mTransportId = transportId;
+ }
return prevTransport;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 07d6b6f..c0d4496 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -61,7 +61,6 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -88,7 +87,6 @@
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
-import android.util.LogPrinter;
import android.util.PrintWriterPrinter;
import android.util.SparseArray;
import android.view.Gravity;
@@ -127,6 +125,7 @@
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
+ static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_SERVICE = localLOGV || false;
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PROCESSES = localLOGV || false;
@@ -10596,7 +10595,7 @@
boolean ordered, boolean sticky, int callingPid, int callingUid) {
intent = new Intent(intent);
- if (DEBUG_BROADCAST) Log.v(
+ if (DEBUG_BROADCAST_LIGHT) Log.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
if ((resultTo != null) && !ordered) {
@@ -11088,7 +11087,7 @@
boolean started = false;
try {
- if (DEBUG_BROADCAST) Log.v(TAG,
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
"Delivering to component " + r.curComponent
+ ": " + r);
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
@@ -11158,12 +11157,22 @@
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
+ if (filter.receiverList.app != null) {
+ // Bump hosting application to no longer be in background
+ // scheduling class. Note that we can't do that if there
+ // isn't an app... but we can only be in that case for
+ // things that directly call the IActivityManager API, which
+ // are already core system stuff so don't matter for this.
+ r.curApp = filter.receiverList.app;
+ filter.receiverList.app.curReceiver = r;
+ updateOomAdjLocked();
+ }
}
try {
- if (DEBUG_BROADCAST) {
+ if (DEBUG_BROADCAST_LIGHT) {
int seq = r.intent.getIntExtra("seq", -1);
- Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
- + " app=" + filter.receiverList.app);
+ Log.i(TAG, "Delivering to " + filter.receiverList.app
+ + " (seq=" + seq + "): " + r);
}
performReceive(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode,
@@ -11177,6 +11186,9 @@
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
+ if (filter.receiverList.app != null) {
+ filter.receiverList.app.curReceiver = null;
+ }
}
}
}
@@ -11200,6 +11212,8 @@
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
+ + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Log.v(TAG,
@@ -11207,6 +11221,8 @@
+ target + ": " + r);
deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
}
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
+ + r);
}
// Now take care of the next serialized one...
@@ -11232,10 +11248,18 @@
}
}
+ boolean looped = false;
+
do {
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ updateOomAdjLocked();
+ }
return;
}
r = mOrderedBroadcasts.get(0);
@@ -11292,9 +11316,13 @@
if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
+ + r);
+
// ... and on to the next...
mOrderedBroadcasts.remove(0);
r = null;
+ looped = true;
continue;
}
} while (r == null);
@@ -11308,6 +11336,8 @@
if (recIdx == 0) {
r.dispatchTime = r.startTime;
+ if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
+ + r);
if (DEBUG_BROADCAST) Log.v(TAG,
"Submitting BROADCAST_TIMEOUT_MSG for "
+ (r.startTime + BROADCAST_TIMEOUT));
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 16aca4d..b2529811 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -103,6 +103,9 @@
assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+ userData.payloadStr = "More @ testing\nis great^|^~woohoo";
+ revBearerData = BearerData.decode(BearerData.encode(bearerData));
+ assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
}
@SmallTest