diff options
68 files changed, 2041 insertions, 4396 deletions
diff --git a/api/current.xml b/api/current.xml index 92540b1f9715..f3e614a11db6 100644 --- a/api/current.xml +++ b/api/current.xml @@ -83874,6 +83874,50 @@ visibility="public" > </field> +<field name="TYPE_MOBILE_DUN" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TYPE_MOBILE_HIPRI" + type="int" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TYPE_MOBILE_MMS" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TYPE_MOBILE_SUPL" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="TYPE_WIFI" type="int" transient="false" diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index 27891ecf6fd1..431a55658b48 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -15,15 +15,4 @@ LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) -COMMANDS = dumpcrash -SYMLINKS := $(addprefix $(TARGET_OUT_EXECUTABLES)/,$(COMMANDS)) -$(SYMLINKS): DUMPSTATE_BINARY := dumpstate -$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk - @echo "Symlink: $@ -> $(DUMPSTATE_BINARY)" - @mkdir -p $(dir $@) - @rm -rf $@ - $(hide) ln -sf $(DUMPSTATE_BINARY) $@ - -ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS) - endif diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index a2b5d8df9f2c..9300915fa458 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -14,361 +14,254 @@ * limitations under the License. */ +#include <errno.h> +#include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> +#include <sys/resource.h> #include <sys/stat.h> -#include <limits.h> -#include <errno.h> -#include <fcntl.h> #include <sys/time.h> -#include <sys/resource.h> +#include <unistd.h> -#include <cutils/sockets.h> -#include "private/android_filesystem_config.h" +#include <cutils/properties.h> +#include "private/android_filesystem_config.h" #define LOG_TAG "dumpstate" #include <utils/Log.h> #include "dumpstate.h" -static char* const gzip_args[] = { "gzip", "-6", 0 }; -static int start_pattern[] = { 150, 0 }; -static int end_pattern[] = { 75, 50, 75, 50, 75, 0 }; - -static struct tm now; - -static void dump_kernel_log(const char *path, const char *title) ; +/* read before root is shed */ +static char cmdline_buf[16384] = "(unknown)"; +static const char *dump_traces_path = NULL; /* dumps the current system state to stdout */ -static void dumpstate(int full) { - if (full) { - PRINT("========================================================"); - PRINT("== dumpstate"); - PRINT("========================================================"); - PRINT("------ MEMORY INFO ------"); - DUMP("/proc/meminfo"); - PRINT("------ CPU INFO ------"); - EXEC7("top", "-n", "1", "-d", "1", "-m", "30", "-t"); - PRINT("------ PROCRANK ------"); - EXEC_XBIN("procrank"); - PRINT("------ VIRTUAL MEMORY STATS ------"); - DUMP("/proc/vmstat"); - PRINT("------ VMALLOC INFO ------"); - DUMP("/proc/vmallocinfo"); - PRINT("------ SLAB INFO ------"); - DUMP("/proc/slabinfo"); - PRINT("------ ZONEINFO ------"); - DUMP("/proc/zoneinfo"); - PRINT("------ SYSTEM LOG ------"); - EXEC4("logcat", "-v", "time", "-d", "*:v"); - PRINT("------ VM TRACES ------"); - DUMP("/data/anr/traces.txt"); - PRINT("------ EVENT LOG TAGS ------"); - DUMP("/etc/event-log-tags"); - PRINT("------ EVENT LOG ------"); - EXEC6("logcat", "-b", "events", "-v", "time", "-d", "*:v"); - PRINT("------ RADIO LOG ------"); - EXEC6("logcat", "-b", "radio", "-v", "time", "-d", "*:v"); - PRINT("------ NETWORK STATE ------"); - PRINT("Interfaces:"); - EXEC("netcfg"); - PRINT(""); - PRINT("Routes:"); - DUMP("/proc/net/route"); -#ifdef FWDUMP_bcm4329 - PRINT("Dump wlan FW log"); - EXEC_XBIN6("su", "root","dhdutil","-i","eth0","upload","/data/local/tmp/wlan_crash.dump"); -#endif - PRINT("------ SYSTEM PROPERTIES ------"); - print_properties(); - PRINT("------ KERNEL LOG ------"); - EXEC("dmesg"); - PRINT("------ KERNEL WAKELOCKS ------"); - DUMP("/proc/wakelocks"); - PRINT("------ KERNEL CPUFREQ ------"); - DUMP("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); - PRINT(""); - PRINT("------ PROCESSES ------"); - EXEC1("ps", "-P"); - PRINT("------ PROCESSES AND THREADS ------"); - EXEC3("ps", "-t", "-p", "-P"); - PRINT("------ LIBRANK ------"); - EXEC_XBIN("librank"); - PRINT("------ BINDER FAILED TRANSACTION LOG ------"); - DUMP("/proc/binder/failed_transaction_log"); - PRINT(""); - PRINT("------ BINDER TRANSACTION LOG ------"); - DUMP("/proc/binder/transaction_log"); - PRINT(""); - PRINT("------ BINDER TRANSACTIONS ------"); - DUMP("/proc/binder/transactions"); - PRINT(""); - PRINT("------ BINDER STATS ------"); - DUMP("/proc/binder/stats"); - PRINT(""); - PRINT("------ BINDER PROCESS STATE: $i ------"); - DUMP_FILES("/proc/binder/proc"); - PRINT("------ FILESYSTEMS ------"); - EXEC("df"); - PRINT("------ PACKAGE SETTINGS ------"); - DUMP("/data/system/packages.xml"); - PRINT("------ PACKAGE UID ERRORS ------"); - DUMP("/data/system/uiderrors.txt"); - - dump_kernel_log("/proc/last_kmsg", "LAST KMSG"); - - PRINT("------ LAST RADIO LOG ------"); - EXEC1("parse_radio_log", "/proc/last_radio_log"); - - dump_kernel_log("/data/dontpanic/apanic_console", - "PANIC CONSOLE"); - dump_kernel_log("/data/dontpanic/apanic_threads", - "PANIC THREADS"); - - PRINT("------ BACKLIGHTS ------"); - DUMP_PROMPT("LCD brightness=", "/sys/class/leds/lcd-backlight/brightness"); - DUMP_PROMPT("Button brightness=", "/sys/class/leds/button-backlight/brightness"); - DUMP_PROMPT("Keyboard brightness=", "/sys/class/leds/keyboard-backlight/brightness"); - DUMP_PROMPT("ALS mode=", "/sys/class/leds/lcd-backlight/als"); - DUMP_PROMPT("LCD driver registers:\n", "/sys/class/leds/lcd-backlight/registers"); +static void dumpstate() { + time_t now = time(NULL); + char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; + char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; + char network[PROPERTY_VALUE_MAX], date[80]; + + property_get("ro.build.display.id", build, "(unknown)"); + property_get("ro.build.fingerprint", fingerprint, "(unknown)"); + property_get("ro.baseband", radio, "(unknown)"); + property_get("ro.bootloader", bootloader, "(unknown)"); + property_get("gsm.operator.alpha", network, "(unknown)"); + strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); + + printf("========================================================\n"); + printf("== dumpstate: %s\n", date); + printf("========================================================\n"); + + printf("\n"); + printf("Build: %s\n", build); + printf("Bootloader: %s\n", bootloader); + printf("Radio: %s\n", radio); + printf("Network: %s\n", network); + + printf("Kernel: "); + dump_file(NULL, "/proc/version"); + printf("Command line: %s\n", strtok(cmdline_buf, "\n")); + printf("\n"); + + dump_file("MEMORY INFO", "/proc/meminfo"); + run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); + run_command("PROCRANK", 20, "procrank", NULL); + dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat"); + dump_file("VMALLOC INFO", "/proc/vmallocinfo"); + dump_file("SLAB INFO", "/proc/slabinfo"); + dump_file("ZONEINFO", "/proc/zoneinfo"); + + run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL); + + /* show the traces we collected in main(), if that was done */ + if (dump_traces_path != NULL) { + dump_file("VM TRACES JUST NOW", dump_traces_path); } - PRINT("========================================================"); - PRINT("== build.prop"); - PRINT("========================================================"); - - /* the crash server parses key-value pairs between the VERSION INFO and - * END lines so we can aggregate crash reports based on this data. - */ - PRINT("------ VERSION INFO ------"); - print_date("currenttime=", &now); - DUMP_PROMPT("kernel.version=", "/proc/version"); - DUMP_PROMPT("kernel.cmdline=", "/proc/cmdline"); - DUMP("/system/build.prop"); - PROPERTY("gsm.version.ril-impl"); - PROPERTY("gsm.version.baseband"); - PROPERTY("gsm.imei"); - PROPERTY("gsm.sim.operator.numeric"); - PROPERTY("gsm.operator.alpha"); - PRINT("------ END ------"); - - if (full) { - PRINT("========================================================"); - PRINT("== dumpsys"); - PRINT("========================================================"); - /* the full dumpsys is starting to take a long time, so we need - to increase its timeout. we really need to do the timeouts in - dumpsys itself... */ - EXEC_TIMEOUT("dumpsys", 60); + + /* only show ANR traces if they're less than 15 minutes old */ + struct stat st; + char anr_traces_path[PATH_MAX]; + property_get("dalvik.vm.stack-trace-file", anr_traces_path, ""); + if (anr_traces_path[0] && !stat(anr_traces_path, &st) && time(NULL) - st.st_mtime < 15 * 60) { + dump_file("VM TRACES AT LAST ANR", anr_traces_path); } -} -/* used to check the file name passed via argv[0] */ -static int check_command_name(const char* name, const char* test) { - int name_length, test_length; + // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); + run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "time", "-d", "*:v", NULL); + run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "time", "-d", "*:v", NULL); - if (!strcmp(name, test)) - return 1; + run_command("NETWORK INTERFACES", 10, "netcfg", NULL); + dump_file("NETWORK ROUTES", "/proc/net/route"); - name_length = strlen(name); - test_length = strlen(test); +#ifdef FWDUMP_bcm4329 + run_command("DUMP WIFI FIRMWARE LOG", 60, + "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL); +#endif - if (name_length > test_length + 2) { - name += (name_length - test_length); - if (name[-1] != '/') - return 0; - if (!strcmp(name, test)) - return 1; - } + print_properties(); + + run_command("KERNEL LOG", 20, "dmesg", NULL); + + dump_file("KERNEL WAKELOCKS", "/proc/wakelocks"); + dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); + + run_command("PROCESSES", 10, "ps", "-P", NULL); + run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); + run_command("LIBRANK", 10, "librank", NULL); + + dump_file("BINDER FAILED TRANSACTION LOG", "/proc/binder/failed_transaction_log"); + dump_file("BINDER TRANSACTION LOG", "/proc/binder/transaction_log"); + dump_file("BINDER TRANSACTIONS", "/proc/binder/transactions"); + dump_file("BINDER STATS", "/proc/binder/stats"); + run_command("BINDER PROCESS STATE", 10, "sh", "-c", "cat /proc/binder/proc/*"); + + run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL); + + dump_file("PACKAGE SETTINGS", "/data/system/packages.xml"); + dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt"); + + dump_file("LAST KMSG", "/proc/last_kmsg"); + run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL); + dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console"); + dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads"); + + printf("----- BACKLIGHTS -----\n"); + printf("LCD brightness="); + dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness"); + printf("Button brightness="); + dump_file(NULL, "/sys/class/leds/button-backlight/brightness"); + printf("Keyboard brightness="); + dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness"); + printf("ALS mode="); + dump_file(NULL, "/sys/class/leds/lcd-backlight/als"); + printf("LCD driver registers:\n"); + dump_file(NULL, "/sys/class/leds/lcd-backlight/registers"); + printf("\n"); + + printf("========================================================\n"); + printf("== Android Framework Services\n"); + printf("========================================================\n"); + + /* the full dumpsys is starting to take a long time, so we need + to increase its timeout. we really need to do the timeouts in + dumpsys itself... */ + run_command("DUMPSYS", 60, "dumpsys", NULL); +} - return 0; + +static void usage() { + fprintf(stderr, "usage: dumpstate [-d] [-o file] [-s] [-z]\n" + " -d: append date to filename (requires -o)\n" + " -o: write to file (instead of stdout)\n" + " -s: write output to control socket (for init)\n" + " -z: gzip output (requires -o)\n"); } int main(int argc, char *argv[]) { - int dumpcrash = check_command_name(argv[0], "dumpcrash"); - int add_date = 0; - char* outfile = 0; - int vibrate = 0; - int compress = 0; - int socket = 0; - int c, fd, vibrate_fd, fds[2]; - char path[PATH_MAX]; - pid_t pid; - gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; + int do_add_date = 0; + int do_compress = 0; + char* use_outfile = 0; + int use_socket = 0; LOGI("begin\n"); /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); - protect_from_oom_killer(); + FILE *oom_adj = fopen("/proc/self/oom_adj", "w"); + if (oom_adj) { + fputs("-17", oom_adj); + fclose(oom_adj); + } - get_time(&now); + /* very first thing, collect VM traces from Dalvik (needs root) */ + dump_traces_path = dump_vm_traces(); - do { - c = getopt(argc, argv, "do:svz"); - if (c == EOF) - break; + int c; + while ((c = getopt(argc, argv, "dho:svz")) != -1) { switch (c) { - case 'd': - add_date = 1; - break; - case 'o': - outfile = optarg; - break; - case 'v': - vibrate = 1; - break; - case 'z': - compress = 1; - break; - case 's': - socket = 1; - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); + case 'd': do_add_date = 1; break; + case 'o': use_outfile = optarg; break; + case 's': use_socket = 1; break; + case 'v': break; // compatibility no-op + case 'z': do_compress = 6; break; + case '?': printf("\n"); + case 'h': + usage(); exit(1); } - } while (1); + } - /* open vibrator before switching user */ - if (vibrate) { - vibrate_fd = open("/sys/class/timed_output/vibrator/enable", O_WRONLY); - if (vibrate_fd > 0) - fcntl(vibrate_fd, F_SETFD, FD_CLOEXEC); - } else - vibrate_fd = -1; + /* open the vibrator before dropping root */ + FILE *vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w"); + if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC); + + /* read /proc/cmdline before dropping root */ + FILE *cmdline = fopen("/proc/cmdline", "r"); + if (cmdline != NULL) { + fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); + fclose(cmdline); + } /* switch to non-root user and group */ + gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; setgroups(sizeof(groups)/sizeof(groups[0]), groups); setuid(AID_SHELL); - /* make it safe to use both printf and STDOUT_FILENO */ - setvbuf(stdout, 0, _IONBF, 0); - - if (socket) { - struct sockaddr addr; - socklen_t alen; - - int s = android_get_control_socket("dumpstate"); - if (s < 0) { - fprintf(stderr, "could not open dumpstate socket\n"); - exit(1); - } - if (listen(s, 4) < 0) { - fprintf(stderr, "could not listen on dumpstate socket\n"); - exit(1); + char path[PATH_MAX], tmp_path[PATH_MAX]; + pid_t gzip_pid = -1; + + if (use_socket) { + redirect_to_socket(stdout, "dumpstate"); + } else if (use_outfile) { + strlcpy(path, use_outfile, sizeof(path)); + if (do_add_date) { + char date[80]; + time_t now = time(NULL); + strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now)); + strlcat(path, date, sizeof(path)); } + strlcat(path, ".txt", sizeof(path)); + if (do_compress) strlcat(path, ".gz", sizeof(path)); + strlcpy(tmp_path, path, sizeof(tmp_path)); + strlcat(tmp_path, ".tmp", sizeof(tmp_path)); + gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); + } - alen = sizeof(addr); - fd = accept(s, &addr, &alen); - if (fd < 0) { - fprintf(stderr, "could not accept dumpstate socket\n"); - exit(1); - } + /* bzzzzzz */ + if (vibrator) { + fputs("150", vibrator); + fflush(vibrator); + } - /* redirect stdout to the socket */ - dup2(fd, STDOUT_FILENO); - close(fd); - } else if (outfile) { - if (strlen(outfile) > sizeof(path) - 100) - exit(1); - - strcpy(path, outfile); - if (add_date) { - char date[260]; - strftime(date, sizeof(date), - "-%Y-%m-%d-%H-%M-%S", - &now); - strcat(path, date); - } - if (compress) - strcat(path, ".gz"); - else - strcat(path, ".txt"); - - /* ensure that all directories in the path exist */ - create_directories(path); - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (fd < 0) - return fd; - - if (compress) { - pipe(fds); - - /* redirect our stdout to the pipe */ - dup2(fds[1], STDOUT_FILENO); - close(fds[1]); - - if ((pid = fork()) < 0) - { - fprintf(stderr, "fork error\n"); - exit(1); - } - - if (pid) { - /* parent case */ - - /* close our copy of the input to gzip */ - close(fds[0]); - /* close our copy of the output file */ - close(fd); - } else { - /* child case */ - - /* redirect our input pipe to stdin */ - dup2(fds[0], STDIN_FILENO); - close(fds[0]); - - /* redirect stdout to the output file */ - dup2(fd, STDOUT_FILENO); - close(fd); - - /* run gzip to postprocess our output */ - execv("/system/bin/gzip", gzip_args); - fprintf(stderr, "execv returned\n"); - } - } else { - /* redirect stdout to the output file */ - dup2(fd, STDOUT_FILENO); - close(fd); + dumpstate(); + + /* bzzz bzzz bzzz */ + if (vibrator) { + int i; + for (i = 0; i < 3; i++) { + fputs("75\n", vibrator); + fflush(vibrator); + usleep((75 + 50) * 1000); } + fclose(vibrator); } - /* else everything will print to stdout */ - if (vibrate) { - vibrate_pattern(vibrate_fd, start_pattern); - } - dumpstate(!dumpcrash); - if (vibrate) { - vibrate_pattern(vibrate_fd, end_pattern); - close(vibrate_fd); + /* wait for gzip to finish, otherwise it might get killed when we exit */ + if (gzip_pid > 0) { + fclose(stdout); + waitpid(gzip_pid, NULL, 0); } - /* so gzip will terminate */ - close(STDOUT_FILENO); + /* rename the (now complete) .tmp file to its final location */ + if (use_outfile && rename(tmp_path, path)) { + fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno)); + } LOGI("done\n"); return 0; } - -static void dump_kernel_log(const char *path, const char *title) - -{ - printf("------ KERNEL %s LOG ------\n", title); - if (access(path, R_OK) < 0) - printf("%s: %s\n", path, strerror(errno)); - else { - struct stat sbuf; - - if (stat(path, &sbuf) < 0) - printf("%s: stat failed (%s)\n", path, strerror(errno)); - else - printf("Harvested %s", ctime(&sbuf.st_mtime)); - - DUMP(path); - } -} diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index ed1f005659cb..6d48a859e15f 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -18,157 +18,24 @@ #define _DUMPSTATE_H_ #include <time.h> - -// Commands time out after 60 seconds -#define TIMEOUT 60 - -#define PRINT(s) printf("%s\n", s) - -#define DUMP(file) dump_file(file) - -#define DUMP_FILES(path) dump_files(path) - -#define DUMP_PROMPT(prompt, file) \ -{ \ - printf(prompt); \ - dump_file(file); \ -} - -#define EXEC(cmd) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC_TIMEOUT(cmd, tmout)\ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, 0 } \ - }; \ - run_command(&c, tmout); \ -} - -#define EXEC_XBIN(cmd) \ -{ \ - static struct Command c = { \ - "/system/xbin/" cmd, \ - { cmd, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC1(cmd, a1) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC2(cmd, a1, a2) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC3(cmd, a1, a2, a3) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, a3, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC4(cmd, a1, a2, a3, a4) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, a3, a4, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC6(cmd, a1, a2, a3, a4, a5, a6) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, a3, a4, a5, a6, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC7(cmd, a1, a2, a3, a4, a5, a6, a7) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, a3, a4, a5, a6, a7, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC8(cmd, a1, a2, a3, a4, a5, a6, a7, a8) \ -{ \ - static struct Command c = { \ - "/system/bin/" cmd, \ - { cmd, a1, a2, a3, a4, a5, a6, a7, a8, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define EXEC_XBIN6(cmd, a1, a2, a3, a4, a5, a6) \ -{ \ - static struct Command c = { \ - "/system/xbin/" cmd, \ - { cmd, a1, a2, a3, a4, a5, a6, 0 } \ - }; \ - run_command(&c, TIMEOUT); \ -} - -#define PROPERTY(name) print_property(name) - -struct Command { - const char* path; - char* const args[]; -}; -typedef struct Command Command; +#include <unistd.h> /* prints the contents of a file */ -int dump_file(const char* path); - -/* prints the contents of all files in a directory */ -void dump_files(const char* path); - -/* forks a command and waits for it to finish */ -int run_command(struct Command* cmd, int timeout); - -/* reads the current time into tm */ -void get_time(struct tm *tm); - -/* prints the date in tm */ -void print_date(const char* prompt, struct tm *tm); +int dump_file(const char *title, const char* path); -/* prints the name and value of a system property */ -int print_property(const char* name); +/* forks a command and waits for it to finish -- terminate args with NULL */ +int run_command(const char *title, int timeout_seconds, const char *command, ...); /* prints all the system properties */ void print_properties(); -/* creates directories as needed for the given path */ -void create_directories(char *path); +/* redirect output to a service control socket */ +void redirect_to_socket(FILE *redirect, const char *service); -/* runs the vibrator using the given pattern */ -void vibrate_pattern(int fd, int* pattern); +/* redirect output to a file, optionally gzipping; returns gzip pid */ +pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level); -/* prevents the OOM killer from killing us */ -void protect_from_oom_killer(); +/* dump Dalvik stack traces, return the trace file location (NULL if none) */ +const char *dump_vm_traces(); #endif /* _DUMPSTATE_H_ */ diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index 60d845f61bf3..fda618cc4c52 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -14,217 +14,337 @@ * limitations under the License. */ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> -#include <unistd.h> +#include <sys/inotify.h> #include <sys/stat.h> -#include <dirent.h> -#include <limits.h> -#include <fcntl.h> -#include <signal.h> #include <sys/time.h> #include <sys/wait.h> +#include <time.h> +#include <unistd.h> #include <cutils/properties.h> -#include <sys/system_properties.h> +#include <cutils/sockets.h> #include "dumpstate.h" /* prints the contents of a file */ -int dump_file(const char* path) { - char buffer[32768]; - int fd, amount_read; - int ret = 0; - - fd = open(path, O_RDONLY); - if (fd < 0) - return fd; - - do { - ret = read(fd, buffer, sizeof(buffer)); - if (ret > 0) - ret = write(STDOUT_FILENO, buffer, ret); - } while (ret > 0); - - buffer[0] = '\n'; - write(STDOUT_FILENO, buffer, 1); - - close(fd); - return ret; -} +int dump_file(const char *title, const char* path) { + char buffer[32768]; + int fd = open(path, O_RDONLY); + if (fd < 0) { + int err = errno; + if (title) printf("----- %s (%s) -----\n", title, path); + printf("*** %s: %s\n", path, strerror(err)); + if (title) printf("\n"); + return -1; + } -/* prints the contents of all files in a directory */ -void dump_files(const char* path) { - DIR* dir; - struct dirent* entry; - char buffer[PATH_MAX]; + if (title) printf("----- %s (%s", title, path); - dir = opendir(path); - if (!dir) { - fprintf(stderr, "could not open directory %s\n", path); - return; + if (title) { + struct stat st; + if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) { + char stamp[80]; + time_t mtime = st.st_mtime; + strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime)); + printf(": %s", stamp); + } + printf(") -----\n"); } - while ((entry = readdir(dir))) { - if (entry->d_type == DT_REG) { - snprintf(buffer, sizeof(buffer), "%s/%s", path, entry->d_name); - dump_file(path); - printf("\n"); + int newline = 0; + for (;;) { + int ret = read(fd, buffer, sizeof(buffer)); + if (ret > 0) { + newline = (buffer[ret - 1] == '\n'); + ret = fwrite(buffer, ret, 1, stdout); } + if (ret <= 0) break; } - closedir(dir); -} - -/* prints the name and value of a system property */ -int print_property(const char* name) { - char value[PROP_VALUE_MAX]; - - __system_property_get(name, value); - printf("%s=%s\n", name, value); + close(fd); + if (!newline) printf("\n"); + if (title) printf("\n"); return 0; } -static pid_t alarm_pid = 0; -static int timed_out = 0; -static void sig_alarm(int sig) -{ - if (alarm_pid) { - kill(alarm_pid, SIGKILL); - timed_out = 1; - alarm_pid = 0; - } -} - /* forks a command and waits for it to finish */ -int run_command(struct Command* cmd, int timeout) { - struct sigaction sa; - pid_t pid; - int status; +int run_command(const char *title, int timeout_seconds, const char *command, ...) { + fflush(stdout); + clock_t start = clock(); + pid_t pid = fork(); - pid = fork(); /* handle error case */ - if (pid < 0) + if (pid < 0) { + printf("*** fork: %s\n", strerror(errno)); return pid; + } /* handle child case */ if (pid == 0) { - int ret = execv(cmd->path, cmd->args); - if (ret) - fprintf(stderr, "execv %s returned %d\n", cmd->path, ret); - exit(ret); + const char *args[1024] = {command}; + size_t arg; + + va_list ap; + va_start(ap, command); + if (title) printf("----- %s (%s", title, command); + for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) { + args[arg] = va_arg(ap, const char *); + if (args[arg] == NULL) break; + if (title) printf(" %s", args[arg]); + } + if (title) printf(") -----\n"); + fflush(stdout); + + execvp(command, (char**) args); + printf("*** exec(%s): %s\n", command, strerror(errno)); + _exit(-1); } /* handle parent case */ - timed_out = 0; - if (timeout) { - memset(&sa, 0, sizeof(sa)); - sa.sa_flags = SA_RESETHAND; - sa.sa_handler = sig_alarm; - sigaction(SIGALRM, &sa, NULL); + for (;;) { + int status; + pid_t p = waitpid(pid, &status, WNOHANG); + float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC; + if (p == pid) { + if (WIFSIGNALED(status)) { + printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); + } else if (WEXITSTATUS(status) > 0) { + printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); + } + if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed); + return status; + } - /* set an alarm so we don't hang forever */ - alarm_pid = pid; - alarm(timeout); - } + if (timeout_seconds && elapsed > timeout_seconds) { + printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid); + kill(pid, SIGTERM); + return -1; + } - waitpid(pid, &status, 0); + usleep(100000); // poll every 0.1 sec + } +} - if (timed_out) - printf("ERROR: command %s timed out\n", cmd->path); +size_t num_props = 0; +static char* props[2000]; - return status; +static void print_prop(const char *key, const char *name, void *user) { + (void) user; + if (num_props < sizeof(props) / sizeof(props[0])) { + char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10]; + snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name); + props[num_props++] = strdup(buf); + } } -/* reads the current time into tm */ -void get_time(struct tm *tm) { - time_t t; - - tzset(); - time(&t); - localtime_r(&t, tm); +static int compare_prop(const void *a, const void *b) { + return strcmp(*(char * const *) a, *(char * const *) b); } -/* prints the date in tm */ -void print_date(const char* prompt, struct tm *tm) { - char strbuf[260]; +/* prints all the system properties */ +void print_properties() { + size_t i; + num_props = 0; + property_list(print_prop, NULL); + qsort(&props, num_props, sizeof(props[0]), compare_prop); - strftime(strbuf, sizeof(strbuf), - "%a %b %e %H:%M:%S %Z %Y", - tm); - printf("%s%s\n", prompt, strbuf); + printf("----- SYSTEM PROPERTIES -----\n"); + for (i = 0; i < num_props; ++i) { + fputs(props[i], stdout); + free(props[i]); + } + printf("\n"); } +/* redirect output to a service control socket */ +void redirect_to_socket(FILE *redirect, const char *service) { + int s = android_get_control_socket(service); + if (s < 0) { + fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno)); + exit(1); + } + if (listen(s, 4) < 0) { + fprintf(stderr, "listen(control socket): %s\n", strerror(errno)); + exit(1); + } -static void print_prop(const char *key, const char *name, - void *user __attribute__((unused))) -{ - printf("[%s]: [%s]\n", key, name); -} + struct sockaddr addr; + socklen_t alen = sizeof(addr); + int fd = accept(s, &addr, &alen); + if (fd < 0) { + fprintf(stderr, "accept(control socket): %s\n", strerror(errno)); + exit(1); + } -/* prints all the system properties */ -void print_properties() { - property_list(print_prop, NULL); + fflush(redirect); + dup2(fd, fileno(redirect)); + close(fd); } -/* creates directories as needed for the given path */ -void create_directories(char *path) -{ +/* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */ +pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) { char *chp = path; /* skip initial slash */ if (chp[0] == '/') chp++; + /* create leading directories, if necessary */ while (chp && chp[0]) { chp = strchr(chp, '/'); if (chp) { *chp = 0; - mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - *chp = '/'; - chp++; + mkdir(path, 0775); /* drwxrwxr-x */ + *chp++ = '/'; } } -} -/* runs the vibrator using the given pattern */ -void vibrate_pattern(int fd, int* pattern) -{ - struct timespec tm; - char buffer[10]; - - while (*pattern) { - /* read vibrate on time */ - int on_time = *pattern++; - snprintf(buffer, sizeof(buffer), "%d", on_time); - write(fd, buffer, strlen(buffer)); - - /* read vibrate off time */ - int delay = *pattern++; - if (delay) { - delay += on_time; - - tm.tv_sec = delay / 1000; - tm.tv_nsec = (delay % 1000) * 1000000; - nanosleep(&tm, NULL); - } else - break; + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "%s: %s\n", path, strerror(errno)); + exit(1); + } + + pid_t gzip_pid = -1; + if (gzip_level > 0) { + int fds[2]; + if (pipe(fds)) { + fprintf(stderr, "pipe: %s\n", strerror(errno)); + exit(1); + } + + fflush(redirect); + fflush(stdout); + + gzip_pid = fork(); + if (gzip_pid < 0) { + fprintf(stderr, "fork: %s\n", strerror(errno)); + exit(1); + } + + if (gzip_pid == 0) { + dup2(fds[0], STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + + close(fd); + close(fds[0]); + close(fds[1]); + + char level[10]; + snprintf(level, sizeof(level), "-%d", gzip_level); + execlp("gzip", "gzip", level, NULL); + fprintf(stderr, "exec(gzip): %s\n", strerror(errno)); + _exit(-1); + } + + close(fd); + close(fds[0]); + fd = fds[1]; } + + dup2(fd, fileno(redirect)); + close(fd); + return gzip_pid; } -/* prevents the OOM killer from killing us */ -void protect_from_oom_killer() -{ - int fd; +/* dump Dalvik stack traces, return the trace file location (NULL if none) */ +const char *dump_vm_traces() { + char traces_path[PROPERTY_VALUE_MAX] = ""; + property_get("dalvik.vm.stack-trace-file", traces_path, ""); + if (!traces_path[0]) return NULL; + + /* move the old traces.txt (if any) out of the way temporarily */ + char anr_traces_path[PATH_MAX]; + strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path)); + strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path)); + rename(traces_path, anr_traces_path); + + /* create a new, empty traces.txt file to receive stack dumps */ + int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC, 0666); /* -rw-rw-rw- */ + if (fd < 0) { + fprintf(stderr, "%s: %s\n", traces_path, strerror(errno)); + return NULL; + } + close(fd); + + /* walk /proc and kill -QUIT all Dalvik processes */ + DIR *proc = opendir("/proc"); + if (proc == NULL) { + fprintf(stderr, "/proc: %s\n", strerror(errno)); + return NULL; + } + + /* use inotify to find when processes are done dumping */ + int ifd = inotify_init(); + if (ifd < 0) { + fprintf(stderr, "inotify_init: %s\n", strerror(errno)); + return NULL; + } + + int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE); + if (wfd < 0) { + fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno)); + return NULL; + } - fd = open("/proc/self/oom_adj", O_WRONLY); - if (fd >= 0) { - // -17 should make us immune to OOM - const char* text = "-17"; - write(fd, text, strlen(text)); + struct dirent *d; + while ((d = readdir(proc))) { + int pid = atoi(d->d_name); + if (pid <= 0) continue; + + /* identify Dalvik: /proc/(pid)/exe = /system/bin/app_process */ + char path[PATH_MAX], data[PATH_MAX]; + snprintf(path, sizeof(path), "/proc/%d/exe", pid); + size_t len = readlink(path, data, sizeof(data) - 1); + if (len <= 0 || memcmp(data, "/system/bin/app_process", 23)) continue; + + /* skip zygote -- it won't dump its stack anyway */ + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + int fd = open(path, O_RDONLY); + len = read(fd, data, sizeof(data) - 1); close(fd); + if (len <= 0 || !memcmp(data, "zygote", 6)) continue; + + if (kill(pid, SIGQUIT)) { + fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); + continue; + } + + /* wait for the writable-close notification from inotify */ + struct pollfd pfd = { ifd, POLLIN, 0 }; + int ret = poll(&pfd, 1, 200); /* 200 msec timeout */ + if (ret < 0) { + fprintf(stderr, "poll: %s\n", strerror(errno)); + } else if (ret == 0) { + fprintf(stderr, "warning: timed out dumping pid %d\n", pid); + } else { + struct inotify_event ie; + read(ifd, &ie, sizeof(ie)); + } } + + close(ifd); + + static char dump_traces_path[PATH_MAX]; + strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path)); + strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path)); + if (rename(traces_path, dump_traces_path)) { + fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno)); + return NULL; + } + + /* replace the saved [ANR] traces.txt file */ + rename(anr_traces_path, traces_path); + return dump_traces_path; } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index b31593277063..5d5bd9ccdd91 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -841,7 +841,14 @@ public class InputMethodService extends AbstractInputMethodService { */ public boolean onEvaluateFullscreenMode() { Configuration config = getResources().getConfiguration(); - return config.orientation == Configuration.ORIENTATION_LANDSCAPE; + if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) { + return false; + } + if (mInputEditorInfo != null + && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) { + return false; + } + return true; } /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a127df01b8e7..30799ec9f3b8 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -129,37 +129,33 @@ public class ConnectivityManager public static final int TYPE_WIFI = 1; /** * An MMS-specific Mobile data connection. This connection may be the - * same as {@link #TYPEMOBILE} but it may be different. This is used + * same as {@link #TYPE_MOBILE} but it may be different. This is used * by applications needing to talk to the carrier's Multimedia Messaging * Service servers. It may coexist with default data connections. - * {@hide} */ public static final int TYPE_MOBILE_MMS = 2; /** * A SUPL-specific Mobile data connection. This connection may be the - * same as {@link #TYPEMOBILE} but it may be different. This is used + * same as {@link #TYPE_MOBILE} but it may be different. This is used * by applications needing to talk to the carrier's Secure User Plane * Location servers for help locating the device. It may coexist with * default data connections. - * {@hide} */ public static final int TYPE_MOBILE_SUPL = 3; /** * A DUN-specific Mobile data connection. This connection may be the - * same as {@link #TYPEMOBILE} but it may be different. This is used + * same as {@link #TYPE_MOBILE} but it may be different. This is used * by applicaitons performing a Dial Up Networking bridge so that * the carrier is aware of DUN traffic. It may coexist with default data * connections. - * {@hide} */ public static final int TYPE_MOBILE_DUN = 4; /** * A High Priority Mobile data connection. This connection is typically - * the same as {@link #TYPEMOBILE} but the routing setup is different. + * the same as {@link #TYPE_MOBILE} but the routing setup is different. * Only requesting processes will have access to the Mobile DNS servers * and only IP's explicitly requested via {@link #requestRouteToHost} - * will route over this interface. - *{@hide} + * will route over this interface if a default route exists. */ public static final int TYPE_MOBILE_HIPRI = 5; /** {@hide} */ diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl index f0526893cff4..e73569adc97e 100644 --- a/core/java/android/os/IMountService.aidl +++ b/core/java/android/os/IMountService.aidl @@ -42,17 +42,17 @@ interface IMountService /** * Mount external storage at given mount point. */ - void mountMedia(String mountPoint); + void mountVolume(String mountPoint); /** * Safely unmount external storage at given mount point. */ - void unmountMedia(String mountPoint); + void unmountVolume(String mountPoint); /** * Format external storage given a mount point. */ - void formatMedia(String mountPoint); + void formatVolume(String mountPoint); /** * Returns true if media notification sounds are enabled. @@ -104,8 +104,7 @@ interface IMountService String[] getSecureContainerList(); /** - * Shuts down the MountService and gracefully unmounts - * all external media. + * Shuts down the MountService and gracefully unmounts all external media. */ void shutdown(); } diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index 3679e478126e..bc76180acab8 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -17,6 +17,8 @@ package android.os; import java.io.IOException; +import android.os.ServiceManager; +import android.os.IMountService; /** * Class that provides access to some of the power management functions. @@ -97,5 +99,19 @@ public class Power * @throws IOException if reboot fails for some reason (eg, lack of * permission) */ - public static native void reboot(String reason) throws IOException; + public static void reboot(String reason) throws IOException + { + IMountService mSvc = IMountService.Stub.asInterface( + ServiceManager.getService("mount")); + + if (mSvc != null) { + try { + mSvc.shutdown(); + } catch (Exception e) { + } + } + rebootNative(reason); + } + + private static native void rebootNative(String reason) throws IOException ; } diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java index e7c19cf451ba..c2928cb9c3a9 100644 --- a/core/java/android/pim/vcard/VCardParser_V21.java +++ b/core/java/android/pim/vcard/VCardParser_V21.java @@ -110,11 +110,11 @@ public class VCardParser_V21 extends VCardParser { private long mTimeHandleBase64; public VCardParser_V21() { - this(VCardConfig.PARSE_TYPE_UNKNOWN); + this(null); } public VCardParser_V21(VCardSourceDetector detector) { - this(detector.getEstimatedType()); + this(detector != null ? detector.getEstimatedType() : VCardConfig.PARSE_TYPE_UNKNOWN); } public VCardParser_V21(int parseType) { diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index 7f947e93207e..509aac56f37c 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -583,14 +583,14 @@ public final class Calendar { * {@link #ACCOUNT_TYPE} identifies a specific account. * <P>Type: TEXT</P> */ - public static final String ACCOUNT_NAME = "account_name"; + public static final String ACCOUNT_NAME = "_sync_account"; /** * The type of account to which this row belongs, which when paired with * {@link #ACCOUNT_NAME} identifies a specific account. * <P>Type: TEXT</P> */ - public static final String ACCOUNT_TYPE = "account_type"; + public static final String ACCOUNT_TYPE = "_sync_account_type"; public static EntityIterator newEntityIterator(Cursor cursor, ContentResolver resolver) { return new EntityIteratorImpl(cursor, resolver); diff --git a/core/java/android/view/TransformGestureDetector.java b/core/java/android/view/TransformGestureDetector.java new file mode 100644 index 000000000000..196716adc0fb --- /dev/null +++ b/core/java/android/view/TransformGestureDetector.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2010 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.view; + +import android.content.Context; +import android.util.Log; +import android.view.GestureDetector.SimpleOnGestureListener; + +/** + * Detects transformation gestures involving more than one pointer ("multitouch") + * using the supplied {@link MotionEvent}s. The {@link OnGestureListener} callback + * will notify users when a particular gesture event has occurred. This class + * should only be used with {@link MotionEvent}s reported via touch. + * + * To use this class: + * <ul> + * <li>Create an instance of the {@code TransformGestureDetector} for your + * {@link View} + * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call + * {@link #onTouchEvent(MotionEvent)}. The methods defined in your + * callback will be executed when the events occur. + * </ul> + * @hide Pending API approval + */ +public class TransformGestureDetector { + /** + * The listener for receiving notifications when gestures occur. + * If you want to listen for all the different gestures then implement + * this interface. If you only want to listen for a subset it might + * be easier to extend {@link SimpleOnGestureListener}. + * + * An application will receive events in the following order: + * One onTransformBegin() + * Zero or more onTransform() + * One onTransformEnd() or onTransformFling() + */ + public interface OnTransformGestureListener { + /** + * Responds to transformation events for a gesture in progress. + * Reported by pointer motion. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return true if the event was handled, false otherwise. + */ + public boolean onTransform(TransformGestureDetector detector); + + /** + * Responds to the beginning of a transformation gesture. Reported by + * new pointers going down. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return true if the event was handled, false otherwise. + */ + public boolean onTransformBegin(TransformGestureDetector detector); + + /** + * Responds to the end of a transformation gesture. Reported by existing + * pointers going up. If the end of a gesture would result in a fling, + * onTransformFling is called instead. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return true if the event was handled, false otherwise. + */ + public boolean onTransformEnd(TransformGestureDetector detector); + + /** + * Responds to the end of a transformation gesture that begins a fling. + * Reported by existing pointers going up. If the end of a gesture + * would not result in a fling, onTransformEnd is called instead. + * + * @param detector The detector reporting the event - use this to + * retrieve extended info about event state. + * @return true if the event was handled, false otherwise. + */ + public boolean onTransformFling(TransformGestureDetector detector); + } + + private static final boolean DEBUG = false; + + private static final int INITIAL_EVENT_IGNORES = 2; + + private Context mContext; + private float mTouchSizeScale; + private OnTransformGestureListener mListener; + private int mVelocityTimeUnits; + private MotionEvent mInitialEvent; + + private MotionEvent mPrevEvent; + private MotionEvent mCurrEvent; + private VelocityTracker mVelocityTracker; + + private float mCenterX; + private float mCenterY; + private float mTransX; + private float mTransY; + private float mPrevFingerDiffX; + private float mPrevFingerDiffY; + private float mCurrFingerDiffX; + private float mCurrFingerDiffY; + private float mRotateDegrees; + private float mCurrLen; + private float mPrevLen; + private float mScaleFactor; + + // Units in pixels. Current value is pulled out of thin air for debugging only. + private float mPointerJumpLimit = 30; + + private int mEventIgnoreCount; + + public TransformGestureDetector(Context context, OnTransformGestureListener listener, + int velocityTimeUnits) { + mContext = context; + mListener = listener; + mTouchSizeScale = context.getResources().getDisplayMetrics().widthPixels/3; + mVelocityTimeUnits = velocityTimeUnits; + mEventIgnoreCount = INITIAL_EVENT_IGNORES; + } + + public TransformGestureDetector(Context context, OnTransformGestureListener listener) { + this(context, listener, 1000); + } + + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getAction(); + boolean handled = true; + + if (mInitialEvent == null) { + // No transform gesture in progress + if ((action == MotionEvent.ACTION_POINTER_1_DOWN || + action == MotionEvent.ACTION_POINTER_2_DOWN) && + event.getPointerCount() >= 2) { + // We have a new multi-finger gesture + mInitialEvent = MotionEvent.obtain(event); + mPrevEvent = MotionEvent.obtain(event); + mVelocityTracker = VelocityTracker.obtain(); + handled = mListener.onTransformBegin(this); + } + } else { + // Transform gesture in progress - attempt to handle it + switch (action) { + case MotionEvent.ACTION_POINTER_1_UP: + case MotionEvent.ACTION_POINTER_2_UP: + // Gesture ended + handled = mListener.onTransformEnd(this); + + reset(); + break; + + case MotionEvent.ACTION_CANCEL: + handled = mListener.onTransformEnd(this); + + reset(); + break; + + case MotionEvent.ACTION_MOVE: + setContext(event); + + // Our first few events can be crazy from some touchscreens - drop them. + if (mEventIgnoreCount == 0) { + mVelocityTracker.addMovement(event); + handled = mListener.onTransform(this); + } else { + mEventIgnoreCount--; + } + + mPrevEvent.recycle(); + mPrevEvent = MotionEvent.obtain(event); + break; + } + } + return handled; + } + + private void setContext(MotionEvent curr) { + mCurrEvent = MotionEvent.obtain(curr); + + mRotateDegrees = -1; + mCurrLen = -1; + mPrevLen = -1; + mScaleFactor = -1; + + final MotionEvent prev = mPrevEvent; + + float px0 = prev.getX(0); + float py0 = prev.getY(0); + float px1 = prev.getX(1); + float py1 = prev.getY(1); + float cx0 = curr.getX(0); + float cy0 = curr.getY(0); + float cx1 = curr.getX(1); + float cy1 = curr.getY(1); + + // Some touchscreens do weird things with pointer values where points are + // too close along one axis. Try to detect this here and smooth things out. + // The main indicator is that we get the X or Y value from the other pointer. + final float dx0 = cx0 - px0; + final float dy0 = cy0 - py0; + final float dx1 = cx1 - px1; + final float dy1 = cy1 - py1; + + if (cx0 == cx1) { + if (Math.abs(dx0) > mPointerJumpLimit) { + cx0 = px0; + } else if (Math.abs(dx1) > mPointerJumpLimit) { + cx1 = px1; + } + } else if (cy0 == cy1) { + if (Math.abs(dy0) > mPointerJumpLimit) { + cy0 = py0; + } else if (Math.abs(dy1) > mPointerJumpLimit) { + cy1 = py1; + } + } + + final float pvx = px1 - px0; + final float pvy = py1 - py0; + final float cvx = cx1 - cx0; + final float cvy = cy1 - cy0; + mPrevFingerDiffX = pvx; + mPrevFingerDiffY = pvy; + mCurrFingerDiffX = cvx; + mCurrFingerDiffY = cvy; + + final float pmidx = px0 + pvx * 0.5f; + final float pmidy = py0 + pvy * 0.5f; + final float cmidx = cx0 + cvx * 0.5f; + final float cmidy = cy0 + cvy * 0.5f; + + mCenterX = cmidx; + mCenterY = cmidy; + mTransX = cmidx - pmidx; + mTransY = cmidy - pmidy; + } + + private void reset() { + if (mInitialEvent != null) { + mInitialEvent.recycle(); + mInitialEvent = null; + } + if (mPrevEvent != null) { + mPrevEvent.recycle(); + mPrevEvent = null; + } + if (mCurrEvent != null) { + mCurrEvent.recycle(); + mCurrEvent = null; + } + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + mEventIgnoreCount = INITIAL_EVENT_IGNORES; + } + + public float getCenterX() { + return mCenterX; + } + + public float getCenterY() { + return mCenterY; + } + + public float getTranslateX() { + return mTransX; + } + + public float getTranslateY() { + return mTransY; + } + + public float getCurrentSpan() { + if (mCurrLen == -1) { + final float cvx = mCurrFingerDiffX; + final float cvy = mCurrFingerDiffY; + mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy); + } + return mCurrLen; + } + + public float getPreviousSpan() { + if (mPrevLen == -1) { + final float pvx = mPrevFingerDiffX; + final float pvy = mPrevFingerDiffY; + mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy); + } + return mPrevLen; + } + + public float getScaleFactor() { + if (mScaleFactor == -1) { + mScaleFactor = getCurrentSpan() / getPreviousSpan(); + } + return mScaleFactor; + } + + public float getRotation() { + throw new UnsupportedOperationException(); + } +} diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java index 5d89c46a3db1..95810807e55b 100644 --- a/core/java/android/view/VelocityTracker.java +++ b/core/java/android/view/VelocityTracker.java @@ -55,12 +55,12 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { } }, 2)); - final float mPastX[] = new float[NUM_PAST]; - final float mPastY[] = new float[NUM_PAST]; - final long mPastTime[] = new long[NUM_PAST]; + final float mPastX[][] = new float[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST]; + final float mPastY[][] = new float[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST]; + final long mPastTime[][] = new long[MotionEvent.BASE_AVAIL_POINTERS][NUM_PAST]; - float mYVelocity; - float mXVelocity; + float mYVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS]; + float mXVelocity[] = new float[MotionEvent.BASE_AVAIL_POINTERS]; private VelocityTracker mNext; @@ -105,7 +105,9 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * Reset the velocity tracker back to its initial state. */ public void clear() { - mPastTime[0] = 0; + for (int i = 0; i < MotionEvent.BASE_AVAIL_POINTERS; i++) { + mPastTime[i][0] = 0; + } } /** @@ -120,18 +122,21 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { public void addMovement(MotionEvent ev) { long time = ev.getEventTime(); final int N = ev.getHistorySize(); - for (int i=0; i<N; i++) { - addPoint(ev.getHistoricalX(i), ev.getHistoricalY(i), - ev.getHistoricalEventTime(i)); + final int pointerCount = ev.getPointerCount(); + for (int p = 0; p < pointerCount; p++) { + for (int i=0; i<N; i++) { + addPoint(p, ev.getHistoricalX(p, i), ev.getHistoricalY(p, i), + ev.getHistoricalEventTime(i)); + } + addPoint(p, ev.getX(p), ev.getY(p), time); } - addPoint(ev.getX(), ev.getY(), time); } - private void addPoint(float x, float y, long time) { + private void addPoint(int pos, float x, float y, long time) { int drop = -1; int i; if (localLOGV) Log.v(TAG, "Adding past y=" + y + " time=" + time); - final long[] pastTime = mPastTime; + final long[] pastTime = mPastTime[pos]; for (i=0; i<NUM_PAST; i++) { if (pastTime[i] == 0) { break; @@ -146,8 +151,8 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { drop = 0; } if (drop == i) drop--; - final float[] pastX = mPastX; - final float[] pastY = mPastY; + final float[] pastX = mPastX[pos]; + final float[] pastY = mPastY[pos]; if (drop >= 0) { if (localLOGV) Log.v(TAG, "Dropping up to #" + drop); final int start = drop+1; @@ -190,44 +195,48 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * must be positive. */ public void computeCurrentVelocity(int units, float maxVelocity) { - final float[] pastX = mPastX; - final float[] pastY = mPastY; - final long[] pastTime = mPastTime; - - // Kind-of stupid. - final float oldestX = pastX[0]; - final float oldestY = pastY[0]; - final long oldestTime = pastTime[0]; - float accumX = 0; - float accumY = 0; - int N=0; - while (N < NUM_PAST) { - if (pastTime[N] == 0) { - break; + for (int pos = 0; pos < MotionEvent.BASE_AVAIL_POINTERS; pos++) { + final float[] pastX = mPastX[pos]; + final float[] pastY = mPastY[pos]; + final long[] pastTime = mPastTime[pos]; + + // Kind-of stupid. + final float oldestX = pastX[0]; + final float oldestY = pastY[0]; + final long oldestTime = pastTime[0]; + float accumX = 0; + float accumY = 0; + int N=0; + while (N < NUM_PAST) { + if (pastTime[N] == 0) { + break; + } + N++; } - N++; - } - // Skip the last received event, since it is probably pretty noisy. - if (N > 3) N--; - - for (int i=1; i < N; i++) { - final int dur = (int)(pastTime[i] - oldestTime); - if (dur == 0) continue; - float dist = pastX[i] - oldestX; - float vel = (dist/dur) * units; // pixels/frame. - if (accumX == 0) accumX = vel; - else accumX = (accumX + vel) * .5f; - - dist = pastY[i] - oldestY; - vel = (dist/dur) * units; // pixels/frame. - if (accumY == 0) accumY = vel; - else accumY = (accumY + vel) * .5f; + // Skip the last received event, since it is probably pretty noisy. + if (N > 3) N--; + + for (int i=1; i < N; i++) { + final int dur = (int)(pastTime[i] - oldestTime); + if (dur == 0) continue; + float dist = pastX[i] - oldestX; + float vel = (dist/dur) * units; // pixels/frame. + if (accumX == 0) accumX = vel; + else accumX = (accumX + vel) * .5f; + + dist = pastY[i] - oldestY; + vel = (dist/dur) * units; // pixels/frame. + if (accumY == 0) accumY = vel; + else accumY = (accumY + vel) * .5f; + } + mXVelocity[pos] = accumX < 0.0f ? Math.max(accumX, -maxVelocity) + : Math.min(accumX, maxVelocity); + mYVelocity[pos] = accumY < 0.0f ? Math.max(accumY, -maxVelocity) + : Math.min(accumY, maxVelocity); + + if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity=" + + mXVelocity + " N=" + N); } - mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity); - mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity); - - if (localLOGV) Log.v(TAG, "Y velocity=" + mYVelocity +" X velocity=" - + mXVelocity + " N=" + N); } /** @@ -237,7 +246,7 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed X velocity. */ public float getXVelocity() { - return mXVelocity; + return mXVelocity[0]; } /** @@ -247,6 +256,32 @@ public final class VelocityTracker implements Poolable<VelocityTracker> { * @return The previously computed Y velocity. */ public float getYVelocity() { - return mYVelocity; + return mYVelocity[0]; + } + + /** + * Retrieve the last computed X velocity. You must first call + * {@link #computeCurrentVelocity(int)} before calling this function. + * + * @param pos Which pointer's velocity to return. + * @return The previously computed X velocity. + * + * @hide Pending API approval + */ + public float getXVelocity(int pos) { + return mXVelocity[pos]; + } + + /** + * Retrieve the last computed Y velocity. You must first call + * {@link #computeCurrentVelocity(int)} before calling this function. + * + * @param pos Which pointer's velocity to return. + * @return The previously computed Y velocity. + * + * @hide Pending API approval + */ + public float getYVelocity(int pos) { + return mYVelocity[pos]; } } diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index c718bac29776..3da18d609ac6 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -111,7 +111,15 @@ public class EditorInfo implements InputType, Parcelable { * flag for you on multi-line text views. */ public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000; - + + /** + * Flag of {@link #imeOptions}: used to request that the IME never go + * into fullscreen mode. Applications need to be aware that the flag is not + * a guarantee, and not all IMEs will respect it. + * @hide + */ + public static final int IME_FLAG_NO_FULLSCREEN = 0x80000000; + /** * Generic unspecified type for {@link #imeOptions}. */ diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index 84a8a3cd359c..a9d6ff6305d0 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -124,6 +124,11 @@ public class MimeTypeMap { return null; } + // Static method called by jni. + private static String mimeTypeFromExtension(String extension) { + return getSingleton().getMimeTypeFromExtension(extension); + } + /** * Return true if the given extension has a registered MIME type. * @param extension A file extension without the leading '.' @@ -344,6 +349,7 @@ public class MimeTypeMap { sMimeTypeMap.loadEntry("application/x-pkcs7-crl", "crl"); sMimeTypeMap.loadEntry("application/x-quicktimeplayer", "qtl"); sMimeTypeMap.loadEntry("application/x-shar", "shar"); + sMimeTypeMap.loadEntry("application/x-shockwave-flash", "swf"); sMimeTypeMap.loadEntry("application/x-stuffit", "sit"); sMimeTypeMap.loadEntry("application/x-sv4cpio", "sv4cpio"); sMimeTypeMap.loadEntry("application/x-sv4crc", "sv4crc"); diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index b6891b1d3b96..6d0be4365efa 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -807,19 +807,21 @@ import java.util.ArrayList; int maxLength = -1; int inputType = EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT; + int imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI + | EditorInfo.IME_FLAG_NO_FULLSCREEN; switch (type) { case 1: // TEXT_AREA single = false; inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT; - setImeOptions(EditorInfo.IME_ACTION_NONE); + imeOptions |= EditorInfo.IME_ACTION_NONE; break; case 2: // PASSWORD inPassword = true; break; case 3: // SEARCH - setImeOptions(EditorInfo.IME_ACTION_SEARCH); + imeOptions |= EditorInfo.IME_ACTION_SEARCH; break; case 4: // EMAIL // TYPE_TEXT_VARIATION_WEB_EDIT_TEXT prevents EMAIL_ADDRESS @@ -858,14 +860,14 @@ import java.util.ArrayList; switch (action) { // Keep in sync with CachedRoot::ImeAction case 0: // NEXT - setImeOptions(EditorInfo.IME_ACTION_NEXT); + imeOptions |= EditorInfo.IME_ACTION_NEXT; break; case 1: // GO - setImeOptions(EditorInfo.IME_ACTION_GO); + imeOptions |= EditorInfo.IME_ACTION_GO; break; case -1: // FAILURE case 2: // DONE - setImeOptions(EditorInfo.IME_ACTION_DONE); + imeOptions |= EditorInfo.IME_ACTION_DONE; break; } } @@ -874,6 +876,7 @@ import java.util.ArrayList; setMaxLength(maxLength); setHorizontallyScrolling(single); setInputType(inputType); + setImeOptions(imeOptions); setInPassword(inPassword); AutoCompleteAdapter adapter = null; setAdapterCustom(adapter); diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java index 000f6c49ab49..2b07ae67c566 100644 --- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java +++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java @@ -102,7 +102,7 @@ public class ExternalMediaFormatActivity extends AlertActivity implements Dialog .getService("mount")); if (mountService != null) { try { - mountService.formatMedia(Environment.getExternalStorageDirectory().toString()); + mountService.formatVolume(Environment.getExternalStorageDirectory().toString()); } catch (RemoteException e) { } } diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp index df5edba4eb76..a46c2dd5b90a 100644 --- a/core/jni/android_os_Power.cpp +++ b/core/jni/android_os_Power.cpp @@ -105,7 +105,7 @@ static JNINativeMethod method_table[] = { { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, { "setScreenState", "(Z)I", (void*)setScreenState }, { "shutdown", "()V", (void*)android_os_Power_shutdown }, - { "reboot", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, + { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, }; int register_android_os_Power(JNIEnv *env) diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 115dd62ed2a4..7d100eb43c3a 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -39,6 +39,10 @@ public class Allocation extends BaseObj { mType = t; } + public Type getType() { + return mType; + } + public void uploadToTexture(int baseMipLevel) { mRS.validate(); mRS.validateSurface(); diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java index 9d70cb27798f..1614ec590cbd 100644 --- a/graphics/java/android/renderscript/Program.java +++ b/graphics/java/android/renderscript/Program.java @@ -111,12 +111,13 @@ public class Program extends BaseObj { mOutputs[mOutputCount++] = e; } - public void addConstant(Type t) throws IllegalStateException { + public int addConstant(Type t) throws IllegalStateException { // Should check for consistant and non-conflicting names... if(mConstantCount >= MAX_CONSTANT) { throw new IllegalArgumentException("Max input count exceeded."); } - mConstants[mConstantCount++] = t; + mConstants[mConstantCount] = t; + return mConstantCount++; } public void setTextureCount(int count) throws IllegalArgumentException { diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index ef30b02c1857..2bc2734fd1be 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -57,6 +57,9 @@ enum { kKeyYear = 'year', // cstring kKeyAlbumArt = 'albA', // compressed image data kKeyAlbumArtMIME = 'alAM', // cstring + kKeyAuthor = 'auth', // cstring + kKeyCDTrackNumber = 'cdtr', // cstring + kKeyDate = 'date', // cstring }; enum { diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index b7639be67b55..656a3c339529 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -95,7 +95,9 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, Program::~Program() { - bindAllocation(NULL); + for (uint32_t ct=0; ct < MAX_UNIFORMS; ct++) { + bindAllocation(NULL, ct); + } delete[] mInputElements; delete[] mOutputElements; @@ -106,15 +108,15 @@ Program::~Program() } -void Program::bindAllocation(Allocation *alloc) +void Program::bindAllocation(Allocation *alloc, uint32_t slot) { - if (mConstants.get() == alloc) { + if (mConstants[slot].get() == alloc) { return; } - if (mConstants.get()) { - mConstants.get()->removeProgramToDirty(this); + if (mConstants[slot].get()) { + mConstants[slot].get()->removeProgramToDirty(this); } - mConstants.set(alloc); + mConstants[slot].set(alloc); if (alloc) { alloc->addProgramToDirty(this); } @@ -239,7 +241,7 @@ namespace renderscript { void rsi_ProgramBindConstants(Context *rsc, RsProgram vp, uint32_t slot, RsAllocation constants) { Program *p = static_cast<Program *>(vp); - p->bindAllocation(static_cast<Allocation *>(constants)); + p->bindAllocation(static_cast<Allocation *>(constants), slot); } void rsi_ProgramBindTexture(Context *rsc, RsProgram vpf, uint32_t slot, RsAllocation a) diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index 4bb7802fa49d..a34e89fa40ff 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -39,7 +39,7 @@ public: const uint32_t * params, uint32_t paramLength); virtual ~Program(); - void bindAllocation(Allocation *); + void bindAllocation(Allocation *, uint32_t slot); virtual void createShader(); bool isUserProgram() const {return mUserShader.size() > 0;} @@ -69,7 +69,7 @@ protected: uint32_t mOutputCount; uint32_t mConstantCount; - ObjectBaseRef<Allocation> mConstants; + ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS]; mutable bool mDirty; String8 mShader; diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index 8e59bc22b05a..cf6d7fcf5f5b 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -69,7 +69,7 @@ void ProgramVertex::setupGL(const Context *rsc, ProgramVertexState *state) } state->mLast.set(this); - const float *f = static_cast<const float *>(mConstants->getPtr()); + const float *f = static_cast<const float *>(mConstants[0]->getPtr()); glMatrixMode(GL_TEXTURE); if (mTextureMatrixEnable) { @@ -116,16 +116,36 @@ void ProgramVertex::createShader() { mShader.setTo(""); - for (uint32_t ct=0; ct < mUniformCount; ct++) { - mShader.append("uniform mat4 "); - mShader.append(mUniformNames[ct]); - mShader.append(";\n"); - } - mShader.append("varying vec4 varColor;\n"); mShader.append("varying vec4 varTex0;\n"); if (mUserShader.length() > 1) { + mShader.append("uniform mat4 "); + mShader.append(mUniformNames[0]); + mShader.append(";\n"); + + for (uint32_t ct=0; ct < mConstantCount; ct++) { + const Element *e = mConstantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + + // Cannot be complex + rsAssert(!f->getFieldCount()); + switch(f->getComponent().getVectorSize()) { + case 1: mShader.append("uniform float UNI_"); break; + case 2: mShader.append("uniform vec2 UNI_"); break; + case 3: mShader.append("uniform vec3 UNI_"); break; + case 4: mShader.append("uniform vec4 UNI_"); break; + default: + rsAssert(0); + } + + mShader.append(e->getFieldName(field)); + mShader.append(";\n"); + } + } + + for (uint32_t ct=0; ct < mInputCount; ct++) { const Element *e = mInputElements[ct].get(); for (uint32_t field=0; field < e->getFieldCount(); field++) { @@ -148,6 +168,12 @@ void ProgramVertex::createShader() } mShader.append(mUserShader); } else { + for (uint32_t ct=0; ct < mUniformCount; ct++) { + mShader.append("uniform mat4 "); + mShader.append(mUniformNames[ct]); + mShader.append(";\n"); + } + for (uint32_t ct=VertexArray::POSITION; ct < mAttribCount; ct++) { mShader.append("attribute vec4 "); mShader.append(mAttribNames[ct]); @@ -155,12 +181,12 @@ void ProgramVertex::createShader() } mShader.append("void main() {\n"); - mShader.append(" gl_Position = uni_MVP * ATTRIB_Position;\n"); + mShader.append(" gl_Position = UNI_MVP * ATTRIB_Position;\n"); mShader.append(" gl_PointSize = ATTRIB_PointSize.x;\n"); mShader.append(" varColor = ATTRIB_Color;\n"); if (mTextureMatrixEnable) { - mShader.append(" varTex0 = uni_TexMatrix * ATTRIB_Texture;\n"); + mShader.append(" varTex0 = UNI_TexMatrix * ATTRIB_Texture;\n"); } else { mShader.append(" varTex0 = ATTRIB_Texture;\n"); } @@ -180,7 +206,7 @@ void ProgramVertex::setupGL2(const Context *rsc, ProgramVertexState *state, Shad glVertexAttrib4f(1, state->color[0], state->color[1], state->color[2], state->color[3]); - const float *f = static_cast<const float *>(mConstants->getPtr()); + const float *f = static_cast<const float *>(mConstants[0]->getPtr()); Matrix mvp; mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); @@ -194,6 +220,54 @@ void ProgramVertex::setupGL2(const Context *rsc, ProgramVertexState *state, Shad &f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET]); } + uint32_t uidx = 1; + for (uint32_t ct=0; ct < mConstantCount; ct++) { + Allocation *alloc = mConstants[ct+1].get(); + if (!alloc) { + continue; + } + + const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); + const Element *e = mConstantTypes[ct]->getElement(); + for (uint32_t field=0; field < e->getFieldCount(); field++) { + const Element *f = e->getField(field); + uint32_t offset = e->getFieldOffsetBytes(field); + int32_t slot = sc->vtxUniformSlot(uidx); + + const float *fd = reinterpret_cast<const float *>(&data[offset]); + + //LOGE("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i", slot, offset, ct, field, uidx); + if (slot >= 0) { + switch(f->getComponent().getVectorSize()) { + case 1: + //LOGE("Uniform 1 = %f", fd[0]); + glUniform1fv(slot, 1, fd); + break; + case 2: + //LOGE("Uniform 2 = %f %f", fd[0], fd[1]); + glUniform2fv(slot, 1, fd); + break; + case 3: + //LOGE("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]); + glUniform3fv(slot, 1, fd); + break; + case 4: + //LOGE("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]); + glUniform4fv(slot, 1, fd); + break; + default: + rsAssert(0); + } + } + uidx ++; + } + } + + for (uint32_t ct=0; ct < mConstantCount; ct++) { + uint32_t glSlot = sc->vtxUniformSlot(ct + 1); + + } + state->mLast.set(this); rsc->checkError("ProgramVertex::setupGL2"); } @@ -208,46 +282,46 @@ void ProgramVertex::addLight(const Light *l) void ProgramVertex::setProjectionMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants->getPtr()); + float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } void ProgramVertex::setModelviewMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants->getPtr()); + float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } void ProgramVertex::setTextureMatrix(const rsc_Matrix *m) const { - float *f = static_cast<float *>(mConstants->getPtr()); + float *f = static_cast<float *>(mConstants[0]->getPtr()); memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix)); mDirty = true; } void ProgramVertex::transformToScreen(const Context *rsc, float *v4out, const float *v3in) const { - float *f = static_cast<float *>(mConstants->getPtr()); + float *f = static_cast<float *>(mConstants[0]->getPtr()); Matrix mvp; mvp.loadMultiply((Matrix *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], (Matrix *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]); mvp.vectorMultiply(v4out, v3in); } -void ProgramVertex::initAddUserAttrib(const Element *e) +void ProgramVertex::initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix) { rsAssert(e->getFieldCount()); for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { const Element *ce = e->getField(ct); if (ce->getFieldCount()) { - initAddUserAttrib(ce); + initAddUserElement(ce, names, count, prefix); } else { - String8 tmp("ATTRIB_"); + String8 tmp(prefix); tmp.append(e->getFieldName(ct)); - mAttribNames[mAttribCount].setTo(tmp.string()); - mAttribCount++; + names[*count].setTo(tmp.string()); + (*count)++; } } } @@ -257,7 +331,13 @@ void ProgramVertex::init(Context *rsc) if (mUserShader.size() > 0) { mAttribCount = 0; for (uint32_t ct=0; ct < mInputCount; ct++) { - initAddUserAttrib(mInputElements[ct].get()); + initAddUserElement(mInputElements[ct].get(), mAttribNames, &mAttribCount, "ATTRIB_"); + } + + mUniformCount = 1; + mUniformNames[0].setTo("UNI_MVP"); + for (uint32_t ct=0; ct < mConstantCount; ct++) { + initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_"); } } else { mAttribCount = 5; @@ -266,11 +346,11 @@ void ProgramVertex::init(Context *rsc) mAttribNames[2].setTo("ATTRIB_Normal"); mAttribNames[3].setTo("ATTRIB_PointSize"); mAttribNames[4].setTo("ATTRIB_Texture"); - } - mUniformCount = 2; - mUniformNames[0].setTo("uni_MVP"); - mUniformNames[1].setTo("uni_TexMatrix"); + mUniformCount = 2; + mUniformNames[0].setTo("UNI_MVP"); + mUniformNames[1].setTo("UNI_TexMatrix"); + } createShader(); } @@ -299,7 +379,7 @@ void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h) mDefaultAlloc.set(alloc); mDefault.set(pv); pv->init(rsc); - pv->bindAllocation(alloc); + pv->bindAllocation(alloc, 0); color[0] = 1.f; color[1] = 1.f; diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index dcb988c1ab5e..28554cc813d6 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -61,7 +61,7 @@ protected: bool mTextureMatrixEnable; private: - void initAddUserAttrib(const Element *e); + void initAddUserElement(const Element *e, String8 *names, uint32_t *count, const char *prefix); }; diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index 8a0ab710e36f..3ba9cee09934 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -973,6 +973,13 @@ static void SC_uploadToBufferObject(RsAllocation va) rsi_AllocationUploadToBufferObject(rsc, va); } +static void SC_syncToGL(RsAllocation va) +{ + GET_TLS(); + Allocation *a = static_cast<Allocation *>(va); + +} + static void SC_ClearColor(float r, float g, float b, float a) { //LOGE("c %f %f %f %f", r, g, b, a); @@ -1321,6 +1328,9 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { { "uploadToBufferObject", (void *)&SC_uploadToBufferObject, "void", "(int)" }, + { "syncToGL", (void *)&SC_syncToGL, + "void", "(int)" }, + { "colorFloatRGBAtoUNorm8", (void *)&SC_colorFloatRGBAtoUNorm8, "int", "(float, float, float, float)" }, { "colorFloatRGBto565", (void *)&SC_colorFloatRGBAto565, diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp index 0d9863de69c4..8ac2487a5aab 100644 --- a/libs/rs/rsShaderCache.cpp +++ b/libs/rs/rsShaderCache.cpp @@ -132,7 +132,7 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag LOGV("vtx U, %s = %d\n", vtx->getUniformName(ct).string(), e->mVtxUniformSlots[ct]); } } - for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) { + for (uint32_t ct=0; ct < frag->getUniformCount(); ct++) { e->mFragUniformSlots[ct] = glGetUniformLocation(pgm, frag->getUniformName(ct)); if (rsc->props.mLogShaders) { LOGV("frag U, %s = %d\n", frag->getUniformName(ct).string(), e->mFragUniformSlots[ct]); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index af57a4c4a973..6563caadb4c6 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1258,22 +1258,24 @@ Exit: static const int NUMVIZBUF = 32; static const int VIZBUFFRAMES = 1024; -static const int TOTALBUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100; +static const int BUFTIMEMSEC = NUMVIZBUF * VIZBUFFRAMES * 1000 / 44100; +static const int TOTALBUFTIMEMSEC = NUMVIZBUF * BUFTIMEMSEC; static bool gotMem = false; +static sp<MemoryHeapBase> heap; static sp<MemoryBase> mem[NUMVIZBUF]; -static uint64_t timeStamp[NUMVIZBUF]; +static uint64_t endTime; static uint64_t lastReadTime; static uint64_t lastWriteTime; static int writeIdx = 0; static void allocVizBufs() { if (!gotMem) { + heap = new MemoryHeapBase(NUMVIZBUF * VIZBUFFRAMES * 2, 0, "snooper"); for (int i=0;i<NUMVIZBUF;i++) { - sp<MemoryHeapBase> heap = new MemoryHeapBase(VIZBUFFRAMES*2, 0, "snooper"); - mem[i] = new MemoryBase(heap, 0, heap->getSize()); - timeStamp[i] = 0; + mem[i] = new MemoryBase(heap, VIZBUFFRAMES * 2 * i, VIZBUFFRAMES * 2); } + endTime = 0; gotMem = true; } } @@ -1290,68 +1292,48 @@ static sp<MemoryBase> getVizBuffer() { allocVizBufs(); - lastReadTime = uptimeMillis() + 100; // account for renderer delay (we shouldn't be doing this here) + lastReadTime = uptimeMillis(); // if there is no recent buffer (yet), just return empty handed if (lastWriteTime + TOTALBUFTIMEMSEC < lastReadTime) { - //LOGI("@@@@ no audio data to look at yet"); + //LOGI("@@@@ no audio data to look at yet: %d + %d < %d", (int)lastWriteTime, TOTALBUFTIMEMSEC, (int)lastReadTime); return NULL; } - char buf[200]; - - int closestIdx = -1; - uint32_t closestTime = 0x7ffffff; - - for (int i = 0; i < NUMVIZBUF; i++) { - uint64_t tsi = timeStamp[i]; - uint64_t diff = tsi > lastReadTime ? tsi - lastReadTime : lastReadTime - tsi; - if (diff < closestTime) { - closestIdx = i; - closestTime = diff; - } - } - - - if (closestIdx >= 0) { - //LOGI("@@@ return buffer %d, %d/%d", closestIdx, uint32_t(lastReadTime), uint32_t(timeStamp[closestIdx])); - return mem[closestIdx]; - } - - // we won't get here, since we either bailed out early, or got a buffer - LOGD("Didn't expect to be here"); - return NULL; -} - -static void storeVizBuf(const void *data, int len, uint64_t time) { - // Copy the data in to the visualizer buffer - // Assume a 16 bit stereo source for now. - short *viz = (short*)mem[writeIdx]->pointer(); - short *src = (short*)data; - for (int i = 0; i < VIZBUFFRAMES; i++) { - // Degrade quality by mixing to mono and clearing the lowest 3 bits. - // This should still be good enough for a visualization - *viz++ = ((int(src[0]) + int(src[1])) >> 1) & ~0x7; - src += 2; - } - timeStamp[writeIdx++] = time; - if (writeIdx >= NUMVIZBUF) { - writeIdx = 0; + int timedelta = endTime - lastReadTime; + if (timedelta < 0) timedelta = 0; + int framedelta = timedelta * 44100 / 1000; + int headIdx = (writeIdx - framedelta) / VIZBUFFRAMES - 1; + while (headIdx < 0) { + headIdx += NUMVIZBUF; } + return mem[headIdx]; } +// Append the data to the vizualization buffer static void makeVizBuffers(const char *data, int len, uint64_t time) { allocVizBufs(); uint64_t startTime = time; const int frameSize = 4; // 16 bit stereo sample is 4 bytes - while (len >= VIZBUFFRAMES * frameSize) { - storeVizBuf(data, len, time); - data += VIZBUFFRAMES * frameSize; - len -= VIZBUFFRAMES * frameSize; - time += 1000 * VIZBUFFRAMES / 44100; + int offset = writeIdx; + int maxoff = heap->getSize() / 2; // in shorts + short *base = (short*)heap->getBase(); + short *src = (short*)data; + while (len > 0) { + + // Degrade quality by mixing to mono and clearing the lowest 3 bits. + // This should still be good enough for a visualization + base[offset++] = ((int(src[0]) + int(src[1])) >> 1) & ~0x7; + src += 2; + len -= frameSize; + if (offset >= maxoff) { + offset = 0; + } } + writeIdx = offset; + endTime = time + (len / frameSize) / 44; //LOGI("@@@ stored buffers from %d to %d", uint32_t(startTime), uint32_t(time)); } @@ -1509,30 +1491,35 @@ void MediaPlayerService::AudioOutput::start() } } +void MediaPlayerService::AudioOutput::snoopWrite(const void* buffer, size_t size) { + // Only make visualization buffers if anyone recently requested visualization data + uint64_t now = uptimeMillis(); + if (lastReadTime + TOTALBUFTIMEMSEC >= now) { + // Based on the current play counter, the number of frames written and + // the current real time we can calculate the approximate real start + // time of the buffer we're about to write. + uint32_t pos; + mTrack->getPosition(&pos); + + // we're writing ahead by this many frames: + int ahead = mNumFramesWritten - pos; + //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency()); + // which is this many milliseconds, assuming 44100 Hz: + ahead /= 44; + + makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency()); + lastWriteTime = now; + } +} + + ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); //LOGV("write(%p, %u)", buffer, size); if (mTrack) { - // Only make visualization buffers if anyone recently requested visualization data - uint64_t now = uptimeMillis(); - if (lastReadTime + TOTALBUFTIMEMSEC >= now) { - // Based on the current play counter, the number of frames written and - // the current real time we can calculate the approximate real start - // time of the buffer we're about to write. - uint32_t pos; - mTrack->getPosition(&pos); - - // we're writing ahead by this many frames: - int ahead = mNumFramesWritten - pos; - //LOGI("@@@ written: %d, playpos: %d, latency: %d", mNumFramesWritten, pos, mTrack->latency()); - // which is this many milliseconds, assuming 44100 Hz: - ahead /= 44; - - makeVizBuffers((const char*)buffer, size, now + ahead + mTrack->latency()); - lastWriteTime = now; - } + snoopWrite(buffer, size); ssize_t ret = mTrack->write(buffer, size); mNumFramesWritten += ret / 4; // assume 16 bit stereo return ret; @@ -1580,6 +1567,7 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) // static void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { + //LOGV("callbackwrapper"); if (event != AudioTrack::EVENT_MORE_DATA) { return; } @@ -1589,6 +1577,7 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( (*me->mCallback)( me, buffer->raw, buffer->size, me->mCallbackCookie); + me->snoopWrite(buffer->raw, buffer->size); } #undef LOG_TAG diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 1c90cf910e26..d1206b46f7e5 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -113,6 +113,7 @@ class MediaPlayerService : public BnMediaPlayerService public: // visualization hack support uint32_t mNumFramesWritten; + void snoopWrite(const void*, size_t); }; class AudioCache : public MediaPlayerBase::AudioSink diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index 5df1e0079b60..48130fc5e2f4 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -729,8 +729,10 @@ sp<MetaData> MP3Extractor::getMetaData() { { kKeyArtist, "TPE1", "TP1" }, { kKeyComposer, "TCOM", "TCM" }, { kKeyGenre, "TCON", "TCO" }, - { kKeyTitle, "TALB", "TAL" }, + { kKeyTitle, "TIT2", "TT2" }, { kKeyYear, "TYE", "TYER" }, + { kKeyAuthor, "TXT", "TEXT" }, + { kKeyCDTrackNumber, "TRK", "TRCK" }, }; static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 143e8ee0e882..b340b298d15d 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -66,6 +66,8 @@ private: uint32_t mCurrentSampleIndex; bool mIsAVC; + size_t mNALLengthSize; + bool mStarted; MediaBufferGroup *mGroup; @@ -76,6 +78,8 @@ private: uint8_t *mSrcBuffer; + size_t parseNALSize(const uint8_t *data) const; + MPEG4Source(const MPEG4Source &); MPEG4Source &operator=(const MPEG4Source &); }; @@ -770,6 +774,7 @@ MPEG4Source::MPEG4Source( mSampleTable(sampleTable), mCurrentSampleIndex(0), mIsAVC(false), + mNALLengthSize(0), mStarted(false), mGroup(NULL), mBuffer(NULL), @@ -780,6 +785,21 @@ MPEG4Source::MPEG4Source( CHECK(success); mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); + + if (mIsAVC) { + uint32_t type; + const void *data; + size_t size; + CHECK(format->findData(kKeyAVCC, &type, &data, &size)); + + const uint8_t *ptr = (const uint8_t *)data; + + CHECK(size >= 7); + CHECK_EQ(ptr[0], 1); // configurationVersion == 1 + + // The number of bytes used to encode the length of a NAL unit. + mNALLengthSize = 1 + (ptr[4] & 3); + } } MPEG4Source::~MPEG4Source() { @@ -837,6 +857,25 @@ sp<MetaData> MPEG4Source::getFormat() { return mFormat; } +size_t MPEG4Source::parseNALSize(const uint8_t *data) const { + switch (mNALLengthSize) { + case 1: + return *data; + case 2: + return U16_AT(data); + case 3: + return ((size_t)data[0] << 16) | U16_AT(&data[1]); + case 4: + return U32_AT(data); + } + + // This cannot happen, mNALLengthSize springs to life by adding 1 to + // a 2-bit integer. + CHECK(!"Should not be here."); + + return 0; +} + status_t MPEG4Source::read( MediaBuffer **out, const ReadOptions *options) { CHECK(mStarted); @@ -919,21 +958,20 @@ status_t MPEG4Source::read( // Each NAL unit is split up into its constituent fragments and // each one of them returned in its own buffer. - CHECK(mBuffer->range_length() >= 2); + CHECK(mBuffer->range_length() >= mNALLengthSize); const uint8_t *src = (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); - size_t nal_size = U16_AT(src); - - CHECK(mBuffer->range_length() >= 2 + nal_size); + size_t nal_size = parseNALSize(src); + CHECK(mBuffer->range_length() >= mNALLengthSize + nal_size); MediaBuffer *clone = mBuffer->clone(); - clone->set_range(mBuffer->range_offset() + 2, nal_size); + clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size); mBuffer->set_range( - mBuffer->range_offset() + 2 + nal_size, - mBuffer->range_length() - 2 - nal_size); + mBuffer->range_offset() + mNALLengthSize + nal_size, + mBuffer->range_length() - mNALLengthSize - nal_size); if (mBuffer->range_length() == 0) { mBuffer->release(); @@ -960,12 +998,12 @@ status_t MPEG4Source::read( uint8_t *dstData = (uint8_t *)mBuffer->data(); size_t srcOffset = 0; size_t dstOffset = 0; + while (srcOffset < size) { - CHECK(srcOffset + 1 < size); - size_t nalLength = - (mSrcBuffer[srcOffset] << 8) | mSrcBuffer[srcOffset + 1]; - CHECK(srcOffset + 1 + nalLength < size); - srcOffset += 2; + CHECK(srcOffset + mNALLengthSize <= size); + size_t nalLength = parseNALSize(&mSrcBuffer[srcOffset]); + srcOffset += mNALLengthSize; + CHECK(srcOffset + nalLength <= size); if (nalLength == 0) { continue; @@ -981,6 +1019,7 @@ status_t MPEG4Source::read( srcOffset += nalLength; dstOffset += nalLength; } + CHECK_EQ(srcOffset, size); mBuffer->set_range(0, dstOffset); mBuffer->meta_data()->clear(); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index be4a9d9baf4b..4cc56e3d3f79 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -275,9 +275,12 @@ void StagefrightMetadataRetriever::parseMetaData() { int to; }; static const Map kMap[] = { + { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER }, { kKeyAlbum, METADATA_KEY_ALBUM }, { kKeyArtist, METADATA_KEY_ARTIST }, + { kKeyAuthor, METADATA_KEY_AUTHOR }, { kKeyComposer, METADATA_KEY_COMPOSER }, + { kKeyDate, METADATA_KEY_DATE }, { kKeyGenre, METADATA_KEY_GENRE }, { kKeyTitle, METADATA_KEY_TITLE }, { kKeyYear, METADATA_KEY_YEAR }, @@ -301,9 +304,16 @@ void StagefrightMetadataRetriever::parseMetaData() { memcpy(mAlbumArt->mData, data, dataSize); } + size_t numTracks = mExtractor->countTracks(); + + char tmp[32]; + sprintf(tmp, "%d", numTracks); + + mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); + // The overall duration is the duration of the longest track. int64_t maxDurationUs = 0; - for (size_t i = 0; i < mExtractor->countTracks(); ++i) { + for (size_t i = 0; i < numTracks; ++i) { sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i); int64_t durationUs; @@ -315,7 +325,6 @@ void StagefrightMetadataRetriever::parseMetaData() { } // The duration value is a string representing the duration in ms. - char tmp[32]; sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000); mMetaData.add(METADATA_KEY_DURATION, String8(tmp)); diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp index c115b184a2d1..f1f7194079e0 100644 --- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp +++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp @@ -161,6 +161,9 @@ status_t MP3Decoder::read( mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data()); if (pvmp3_framedecoder(mConfig, mDecoderBuf) != NO_DECODING_ERROR) { + buffer->release(); + buffer = NULL; + mInputBuffer->release(); mInputBuffer = NULL; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestSuite.java b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java index f3d1c5eebe72..6fbf713d3f7a 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestSuite.java +++ b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java @@ -1,5 +1,6 @@ + /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2007 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. @@ -14,18 +15,10 @@ * limitations under the License. */ -package com.android.unit_tests.vcard; - -import com.android.unit_tests.AndroidTests; - -import android.test.suitebuilder.TestSuiteBuilder; +package com.android.server; -import junit.framework.TestSuite; +interface INativeDaemonConnectorCallbacks { -public class VCardTestSuite extends TestSuite { - public static TestSuite suite() { - TestSuiteBuilder suiteBuilder = new TestSuiteBuilder(AndroidTests.class); - suiteBuilder.includeAllPackagesUnderHere(); - return suiteBuilder.build(); - } -}
\ No newline at end of file + void onDaemonConnected(); + boolean onEvent(int code, String raw, String[] cooked); +} diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java deleted file mode 100644 index 9443ff84921f..000000000000 --- a/services/java/com/android/server/MountListener.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.net.LocalSocketAddress; -import android.net.LocalSocket; -import android.os.Environment; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.util.Config; -import android.util.Log; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.lang.IllegalStateException; - -import java.util.List; -import java.util.ArrayList; -import java.util.ListIterator; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Vold Connection class - */ -final class MountListener implements Runnable { - private static final String TAG = "MountListener"; - private static final String VOLD_SOCKET = "vold"; - private static final int RESPONSE_QUEUE_SIZE = 10; - - private MountService mService; - private BlockingQueue<String> mResponseQueue; - private OutputStream mOutputStream; - - class ResponseCode { - public static final int ActionInitiated = 100; - public static final int VolumeListResult = 110; - public static final int AsecListResult = 111; - - public static final int CommandOkay = 200; - public static final int ShareAvailabilityResult = 210; - public static final int AsecPathResult = 211; - - public static final int UnsolicitedInformational = 600; - public static final int VolumeStateChange = 605; - public static final int VolumeMountFailedBlank = 610; - public static final int VolumeMountFailedDamaged = 611; - public static final int VolumeMountFailedNoMedia = 612; - public static final int ShareAvailabilityChange = 620; - public static final int VolumeDiskInserted = 630; - public static final int VolumeDiskRemoved = 631; - public static final int VolumeBadRemoval = 632; - } - - MountListener(MountService service) { - mService = service; - mResponseQueue = new LinkedBlockingQueue<String>(RESPONSE_QUEUE_SIZE); - } - - public void run() { - // Vold does not run in the simulator, so fake out a mounted event to trigger the Media Scanner - if ("simulator".equals(SystemProperties.get("ro.product.device"))) { - mService.notifyMediaMounted(Environment.getExternalStorageDirectory().getPath(), false); - return; - } - - try { - while (true) { - listenToSocket(); - } - } catch (Throwable t) { - Log.e(TAG, "Fatal error " + t + " in MountListener thread!"); - } - } - - private void listenToSocket() { - LocalSocket socket = null; - - try { - socket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET, - LocalSocketAddress.Namespace.RESERVED); - - socket.connect(address); - mService.onVoldConnected(); - - InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); - - byte[] buffer = new byte[4096]; - - while (true) { - int count = inputStream.read(buffer); - if (count < 0) break; - - int start = 0; - for (int i = 0; i < count; i++) { - if (buffer[i] == 0) { - String event = new String(buffer, start, i - start); -// Log.d(TAG, "Got packet {" + event + "}"); - - String[] tokens = event.split(" "); - try { - int code = Integer.parseInt(tokens[0]); - - if (code >= ResponseCode.UnsolicitedInformational) { - try { - handleUnsolicitedEvent(code, event, tokens); - } catch (Exception ex) { - Log.e(TAG, String.format( - "Error handling '%s'", event), ex); - } - } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Log.e(TAG, "InterruptedException"); - } - } - } catch (NumberFormatException nfe) { - Log.w(TAG, - "Unknown msg from Vold '" + event + "'"); - } - start = i + 1; - } - } - } - } catch (IOException ex) { - Log.e(TAG, "IOException in listenToSocket"); - } - - synchronized (this) { - if (mOutputStream != null) { - try { - mOutputStream.close(); - } catch (IOException e) { - Log.w(TAG, "IOException closing output stream"); - } - - mOutputStream = null; - } - } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - Log.w(TAG, "IOException closing socket"); - } - - Log.e(TAG, "Failed to connect to Vold", new IllegalStateException()); - SystemClock.sleep(5000); - } - - private void handleUnsolicitedEvent(int code, String raw, - String[] cooked) throws IllegalStateException { -// Log.d(TAG, "unsolicited {" + raw + "}"); - if (code == ResponseCode.VolumeStateChange) { - // FMT: NNN Volume <label> <mountpoint> state changed from <old_#> (<old_str>) to <new_#> (<new_str>) - mService.notifyVolumeStateChange(cooked[2], cooked[3], - Integer.parseInt(cooked[7]), - Integer.parseInt(cooked[10])); - } else if (code == ResponseCode.VolumeMountFailedBlank) { - // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems - mService.notifyMediaNoFs(cooked[3]); - // FMT: NNN Volume <label> <mountpoint> mount failed - no media - } else if (code == ResponseCode.VolumeMountFailedNoMedia) { - mService.notifyMediaRemoved(cooked[3]); - } else if (code == ResponseCode.VolumeMountFailedDamaged) { - // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed - mService.notifyMediaUnmountable(cooked[3]); - } else if (code == ResponseCode.ShareAvailabilityChange) { - // FMT: NNN Share method <method> now <available|unavailable> - boolean avail = false; - if (cooked[5].equals("available")) { - avail = true; - } - mService.notifyShareAvailabilityChange(cooked[3], avail); - } else if (code == ResponseCode.VolumeDiskInserted) { - // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) - mService.notifyMediaInserted(cooked[3]); - } else if (code == ResponseCode.VolumeDiskRemoved) { - // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) - mService.notifyMediaRemoved(cooked[3]); - } else if (code == ResponseCode.VolumeBadRemoval) { - // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) - mService.notifyMediaBadRemoval(cooked[3]); - } else { - Log.w(TAG, "Unhandled event {" + raw + "}"); - } - } - - - private void sendCommand(String command) { - sendCommand(command, null); - } - - /** - * Sends a command to Vold with a single argument - * - * @param command The command to send to the mount service daemon - * @param argument The argument to send with the command (or null) - */ - private void sendCommand(String command, String argument) { - synchronized (this) { - // Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}"); - if (mOutputStream == null) { - Log.e(TAG, "No connection to Vold", new IllegalStateException()); - } else { - StringBuilder builder = new StringBuilder(command); - if (argument != null) { - builder.append(argument); - } - builder.append('\0'); - - try { - mOutputStream.write(builder.toString().getBytes()); - } catch (IOException ex) { - Log.e(TAG, "IOException in sendCommand", ex); - } - } - } - } - - private synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException { - sendCommand(cmd); - - ArrayList<String> response = new ArrayList<String>(); - boolean complete = false; - int code = -1; - - while (!complete) { - try { - String line = mResponseQueue.take(); -// Log.d(TAG, "Removed off queue -> " + line); - String[] tokens = line.split(" "); - code = Integer.parseInt(tokens[0]); - - if ((code >= 200) && (code < 600)) - complete = true; - response.add(line); - } catch (InterruptedException ex) { - Log.e(TAG, "InterruptedException"); - } - } - - if (code >= 400 && code < 600) { - throw new IllegalStateException(String.format( - "Command %s failed with code %d", - cmd, code)); - } - return response; - } - - boolean getShareAvailable(String method) throws IllegalStateException { - ArrayList<String> rsp = doCommand("share_available " + method); - - for (String line : rsp) { - String []tok = line.split(" "); - int code = Integer.parseInt(tok[0]); - if (code == ResponseCode.ShareAvailabilityResult) { - if (tok[2].equals("available")) - return true; - return false; - } else { - throw new IllegalStateException(String.format("Unexpected response code %d", code)); - } - } - throw new IllegalStateException("Got an empty response"); - } - - /** - * Enables or disables USB mass storage support. - * - * @param enable true to enable USB mass storage support - */ - void setShareMethodEnabled(String mountPoint, String method, - boolean enable) throws IllegalStateException { - doCommand((enable ? "" : "un") + "share " + mountPoint + " " + method); - } - - /** - * Mount media at given mount point. - */ - public void mountVolume(String label) throws IllegalStateException { - doCommand("mount " + label); - } - - /** - * Unmount media at given mount point. - */ - public void unmountVolume(String label) throws IllegalStateException { - doCommand("unmount " + label); - } - - /** - * Format media at given mount point. - */ - public void formatVolume(String label) throws IllegalStateException { - doCommand("format " + label); - } - - public String createAsec(String id, int sizeMb, String fstype, String key, - int ownerUid) throws IllegalStateException { - String cmd = String.format("create_asec %s %d %s %s %d", - id, sizeMb, fstype, key, ownerUid); - doCommand(cmd); - return getAsecPath(id); - } - - public void finalizeAsec(String id) throws IllegalStateException { - doCommand("finalize_asec " + id); - } - - public void destroyAsec(String id) throws IllegalStateException { - doCommand("destroy_asec " + id); - } - - public String mountAsec(String id, String key, int ownerUid) throws IllegalStateException { - String cmd = String.format("mount_asec %s %s %d", - id, key, ownerUid); - doCommand(cmd); - return getAsecPath(id); - } - - public String getAsecPath(String id) throws IllegalStateException { - ArrayList<String> rsp = doCommand("asec_path " + id); - - for (String line : rsp) { - String []tok = line.split(" "); - int code = Integer.parseInt(tok[0]); - if (code == ResponseCode.AsecPathResult) { - return tok[1]; - } else { - throw new IllegalStateException(String.format("Unexpected response code %d", code)); - } - } - throw new IllegalStateException("Got an empty response"); - } - - public String[] listAsec() throws IllegalStateException { - ArrayList<String> rsp = doCommand("list_asec"); - - String[] rdata = new String[rsp.size()]; - int idx = 0; - - for (String line : rsp) { - String []tok = line.split(" "); - int code = Integer.parseInt(tok[0]); - if (code == ResponseCode.AsecListResult) { - rdata[idx++] = tok[1]; - } else if (code == ResponseCode.CommandOkay) { - return rdata; - } else { - throw new IllegalStateException(String.format("Unexpected response code %d", code)); - } - } - throw new IllegalStateException("Got an empty response"); - } -} diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index cd17bd2e3ecf..c8a691526058 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -33,6 +33,7 @@ import android.os.UEventObserver; import android.os.Handler; import android.text.TextUtils; import android.util.Log; +import java.util.ArrayList; import android.provider.Settings; import android.content.ContentResolver; @@ -46,7 +47,8 @@ import java.lang.IllegalStateException; * MountService implements an to the mount service daemon * @hide */ -class MountService extends IMountService.Stub { +class MountService extends IMountService.Stub + implements INativeDaemonConnectorCallbacks { private static final String TAG = "MountService"; @@ -63,15 +65,33 @@ class MountService extends IMountService.Stub { public static final int SharedMnt = 8; } + class VoldResponseCode { + public static final int VolumeListResult = 110; + public static final int AsecListResult = 111; + + public static final int ShareAvailabilityResult = 210; + public static final int AsecPathResult = 211; + + public static final int VolumeStateChange = 605; + public static final int VolumeMountFailedBlank = 610; + public static final int VolumeMountFailedDamaged = 611; + public static final int VolumeMountFailedNoMedia = 612; + public static final int ShareAvailabilityChange = 620; + public static final int VolumeDiskInserted = 630; + public static final int VolumeDiskRemoved = 631; + public static final int VolumeBadRemoval = 632; + } + + /** * Binder context for this service */ private Context mContext; /** - * listener object for communicating with the mount service daemon + * connectorr object for communicating with vold */ - private MountListener mListener; + private NativeDaemonConnector mConnector; /** * The notification that is shown when a USB mass storage host @@ -119,12 +139,12 @@ class MountService extends IMountService.Stub { mContext = context; // Register a BOOT_COMPLETED handler so that we can start - // MountListener. We defer the startup so that we don't + // our NativeDaemonConnector. We defer the startup so that we don't // start processing events before we ought-to mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); - mListener = new MountListener(this); + mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); mShowSafeUnmountNotificationWhenUnmounted = false; mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1"); @@ -202,7 +222,18 @@ class MountService extends IMountService.Stub { String action = intent.getAction(); if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { - Thread thread = new Thread(mListener, MountListener.class.getName()); + /* + * Vold does not run in the simulator, so fake out a mounted + * event to trigger MediaScanner + */ + if ("simulator".equals(SystemProperties.get("ro.product.device"))) { + notifyMediaMounted( + Environment.getExternalStorageDirectory().getPath(), false); + return; + } + + Thread thread = new Thread( + mConnector, NativeDaemonConnector.class.getName()); thread.start(); } } @@ -215,7 +246,7 @@ class MountService extends IMountService.Stub { throw new SecurityException("Requires SHUTDOWN permission"); } - Log.i(TAG, "Shutting down"); + Log.d(TAG, "Shutting down"); String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_SHARED)) { @@ -258,7 +289,21 @@ class MountService extends IMountService.Stub { */ try { String m = Environment.getExternalStorageDirectory().toString(); - unmountMedia(m); + unmountVolume(m); + + int retries = 12; + while (!state.equals(Environment.MEDIA_UNMOUNTED) && (retries-- >=0)) { + try { + Thread.sleep(1000); + } catch (InterruptedException iex) { + Log.e(TAG, "Interrupted while waiting for media", iex); + break; + } + state = Environment.getExternalStorageState(); + } + if (retries == 0) { + Log.e(TAG, "Timed out waiting for media to unmount"); + } } catch (Exception e) { Log.e(TAG, "external storage unmount failed", e); } @@ -288,17 +333,14 @@ class MountService extends IMountService.Stub { String vs = getVolumeState(vp); if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { - mListener.unmountVolume(vp); + unmountVolume(vp); updateUsbMassStorageNotification(true, false); } - mListener.setShareMethodEnabled(Environment - .getExternalStorageDirectory() - .getPath(), - "ums", enable); + setShareMethodEnabled(vp, "ums", enable); mUmsEnabled = enable; if (!enable) { - mountMedia(vp); + mountVolume(vp); if (mPromptUms) { updateUsbMassStorageNotification(false, false); } else { @@ -338,19 +380,19 @@ class MountService extends IMountService.Stub { /** * Attempt to mount external media */ - public void mountMedia(String mountPath) throws IllegalStateException { + public void mountVolume(String mountPath) throws IllegalStateException { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission"); } - mListener.mountVolume(mountPath); + mConnector.doCommand(String.format("mount %s", mountPath)); } /** * Attempt to unmount external media to prepare for eject */ - public void unmountMedia(String mountPath) throws IllegalStateException { + public void unmountVolume(String mountPath) throws IllegalStateException { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) != PackageManager.PERMISSION_GRANTED) { @@ -361,24 +403,52 @@ class MountService extends IMountService.Stub { // to display the notification mShowSafeUnmountNotificationWhenUnmounted = true; - // tell mountd to unmount the media - mListener.unmountVolume(mountPath); + mConnector.doCommand(String.format("unmount %s", mountPath)); } /** * Attempt to format external media */ - public void formatMedia(String formatPath) throws IllegalStateException { + public void formatVolume(String formatPath) throws IllegalStateException { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission"); } - mListener.formatVolume(formatPath); + mConnector.doCommand(String.format("format %s", formatPath)); + } + + boolean getShareAvailable(String method) throws IllegalStateException { + ArrayList<String> rsp = mConnector.doCommand("share_available " + method); + + for (String line : rsp) { + String []tok = line.split(" "); + int code = Integer.parseInt(tok[0]); + if (code == VoldResponseCode.ShareAvailabilityResult) { + if (tok[2].equals("available")) + return true; + return false; + } else { + throw new IllegalStateException(String.format("Unexpected response code %d", code)); + } + } + throw new IllegalStateException("Got an empty response"); } /** + * Enables or disables USB mass storage support. + * + * @param enable true to enable USB mass storage support + */ + void setShareMethodEnabled(String mountPoint, String method, + boolean enable) throws IllegalStateException { + mConnector.doCommand(String.format( + "%sshare %s %s", (enable ? "" : "un"), mountPoint, method)); + } + + + /** * Returns true if we're playing media notification sounds. */ public boolean getPlayNotificationSounds() { @@ -403,7 +473,7 @@ class MountService extends IMountService.Stub { Log.w(TAG, "Multiple volumes not currently supported"); return; } - Log.w(TAG, "State for {" + mountPoint + "} = {" + state + "}"); + Log.i(TAG, "State for {" + mountPoint + "} = {" + state + "}"); mLegacyState = state; } @@ -441,14 +511,18 @@ class MountService extends IMountService.Stub { } } - void onVoldConnected() { + /** + * + * Callback from NativeDaemonConnector + */ + public void onDaemonConnected() { new Thread() { public void run() { try { if (!getVolumeState(Environment.getExternalStorageDirectory().getPath()) .equals(Environment.MEDIA_MOUNTED)) { try { - mountMedia(Environment.getExternalStorageDirectory().getPath()); + mountVolume(Environment.getExternalStorageDirectory().getPath()); } catch (Exception ex) { Log.w(TAG, "Connection-mount failed"); } @@ -460,7 +534,7 @@ class MountService extends IMountService.Stub { } try { - boolean avail = mListener.getShareAvailable("ums"); + boolean avail = getShareAvailable("ums"); notifyShareAvailabilityChange("ums", avail); } catch (Exception ex) { Log.w(TAG, "Failed to get share availability"); @@ -469,6 +543,49 @@ class MountService extends IMountService.Stub { }.start(); } + /** + * + * Callback from NativeDaemonConnector + */ + public boolean onEvent(int code, String raw, String[] cooked) { + // Log.d(TAG, "event {" + raw + "}"); + if (code == VoldResponseCode.VolumeStateChange) { + // FMT: NNN Volume <label> <mountpoint> state changed + // from <old_#> (<old_str>) to <new_#> (<new_str>) + notifyVolumeStateChange( + cooked[2], cooked[3], Integer.parseInt(cooked[7]), + Integer.parseInt(cooked[10])); + } else if (code == VoldResponseCode.VolumeMountFailedBlank) { + // FMT: NNN Volume <label> <mountpoint> mount failed - no supported file-systems + notifyMediaNoFs(cooked[3]); + // FMT: NNN Volume <label> <mountpoint> mount failed - no media + } else if (code == VoldResponseCode.VolumeMountFailedNoMedia) { + notifyMediaRemoved(cooked[3]); + } else if (code == VoldResponseCode.VolumeMountFailedDamaged) { + // FMT: NNN Volume <label> <mountpoint> mount failed - filesystem check failed + notifyMediaUnmountable(cooked[3]); + } else if (code == VoldResponseCode.ShareAvailabilityChange) { + // FMT: NNN Share method <method> now <available|unavailable> + boolean avail = false; + if (cooked[5].equals("available")) { + avail = true; + } + notifyShareAvailabilityChange(cooked[3], avail); + } else if (code == VoldResponseCode.VolumeDiskInserted) { + // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) + notifyMediaInserted(cooked[3]); + } else if (code == VoldResponseCode.VolumeDiskRemoved) { + // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) + notifyMediaRemoved(cooked[3]); + } else if (code == VoldResponseCode.VolumeBadRemoval) { + // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) + notifyMediaBadRemoval(cooked[3]); + } else { + return false; + } + return true; + } + void notifyVolumeStateChange(String label, String mountPoint, int oldState, int newState) throws IllegalStateException { String vs = getVolumeState(mountPoint); @@ -573,7 +690,7 @@ class MountService extends IMountService.Stub { new Thread() { public void run() { try { - mountMedia(path); + mountVolume(path); } catch (Exception ex) { Log.w(TAG, "Failed to mount media on insertion", ex); } @@ -889,29 +1006,62 @@ class MountService extends IMountService.Stub { } public String[] getSecureContainerList() throws IllegalStateException { - return mListener.listAsec(); + ArrayList<String> rsp = mConnector.doCommand("list_asec"); + + String[] rdata = new String[rsp.size()]; + int idx = 0; + + for (String line : rsp) { + String []tok = line.split(" "); + int code = Integer.parseInt(tok[0]); + if (code == VoldResponseCode.AsecListResult) { + rdata[idx++] = tok[1]; + } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { + return rdata; + } else { + throw new IllegalStateException(String.format("Unexpected response code %d", code)); + } + } + throw new IllegalStateException("Got an empty response"); } public String createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid) throws IllegalStateException { - return mListener.createAsec(id, sizeMb, fstype, key, ownerUid); + String cmd = String.format("create_asec %s %d %s %s %d", + id, sizeMb, fstype, key, ownerUid); + mConnector.doCommand(cmd); + return getSecureContainerPath(id); } public void finalizeSecureContainer(String id) throws IllegalStateException { - mListener.finalizeAsec(id); + mConnector.doCommand(String.format("finalize_asec %s", id)); } public void destroySecureContainer(String id) throws IllegalStateException { - mListener.destroyAsec(id); + mConnector.doCommand(String.format("destroy_asec %s", id)); } - public String mountSecureContainer(String id, String key, int ownerUid) throws IllegalStateException { - return mListener.mountAsec(id, key, ownerUid); + public String mountSecureContainer(String id, String key, + int ownerUid) throws IllegalStateException { + String cmd = String.format("mount_asec %s %s %d", + id, key, ownerUid); + mConnector.doCommand(cmd); + return getSecureContainerPath(id); } public String getSecureContainerPath(String id) throws IllegalStateException { - return mListener.getAsecPath(id); - } + ArrayList<String> rsp = mConnector.doCommand("asec_path " + id); + for (String line : rsp) { + String []tok = line.split(" "); + int code = Integer.parseInt(tok[0]); + if (code == VoldResponseCode.AsecPathResult) { + return tok[1]; + } else { + throw new IllegalStateException(String.format("Unexpected response code %d", code)); + } + } + throw new IllegalStateException("Got an empty response"); + } } diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java new file mode 100644 index 000000000000..da3e562fb540 --- /dev/null +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.net.LocalSocketAddress; +import android.net.LocalSocket; +import android.os.Environment; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.util.Config; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.lang.IllegalStateException; + +import java.util.List; +import java.util.ArrayList; +import java.util.ListIterator; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Generic connector class for interfacing with a native + * daemon which uses the libsysutils FrameworkListener + * protocol. + */ +final class NativeDaemonConnector implements Runnable { + + private BlockingQueue<String> mResponseQueue; + private OutputStream mOutputStream; + private String TAG = "NativeDaemonConnector"; + private String mSocket; + private INativeDaemonConnectorCallbacks mCallbacks; + + class ResponseCode { + public static final int ActionInitiated = 100; + + public static final int CommandOkay = 200; + + // The range of 400 -> 599 is reserved for cmd failures + public static final int OperationFailed = 400; + public static final int CommandSyntaxError = 500; + public static final int CommandParameterError = 501; + + public static final int UnsolicitedInformational = 600; + + // + public static final int FailedRangeStart = 400; + public static final int FailedRangeEnd = 599; + } + + NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, + String socket, int responseQueueSize, String logTag) { + mCallbacks = callbacks; + if (logTag != null) + TAG = logTag; + mSocket = socket; + mResponseQueue = new LinkedBlockingQueue<String>(responseQueueSize); + } + + public void run() { + + while (true) { + try { + listenToSocket(); + } catch (Exception e) { + Log.e(TAG, "Error in NativeDaemonConnector", e); + SystemClock.sleep(1000); + } + } + } + + private void listenToSocket() { + LocalSocket socket = null; + + try { + socket = new LocalSocket(); + LocalSocketAddress address = new LocalSocketAddress(mSocket, + LocalSocketAddress.Namespace.RESERVED); + + socket.connect(address); + mCallbacks.onDaemonConnected(); + + InputStream inputStream = socket.getInputStream(); + mOutputStream = socket.getOutputStream(); + + byte[] buffer = new byte[4096]; + + while (true) { + int count = inputStream.read(buffer); + if (count < 0) break; + + int start = 0; + for (int i = 0; i < count; i++) { + if (buffer[i] == 0) { + String event = new String(buffer, start, i - start); +// Log.d(TAG, "Got packet {" + event + "}"); + + String[] tokens = event.split(" "); + try { + int code = Integer.parseInt(tokens[0]); + + if (code >= ResponseCode.UnsolicitedInformational) { + try { + if (!mCallbacks.onEvent(code, event, tokens)) { + Log.w(TAG, String.format( + "Unhandled event (%s)", event)); + } + } catch (Exception ex) { + Log.e(TAG, String.format( + "Error handling '%s'", event), ex); + } + } else { + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Log.e(TAG, "Failed to put response onto queue", ex); + } + } + } catch (NumberFormatException nfe) { + Log.w(TAG, String.format("Bad msg (%s)", event)); + } + start = i + 1; + } + } + } + } catch (IOException ex) { + Log.e(TAG, "Communications error", ex); + } + + synchronized (this) { + if (mOutputStream != null) { + try { + mOutputStream.close(); + } catch (IOException e) { + Log.w(TAG, "Failed closing output stream", e); + } + + mOutputStream = null; + } + } + + try { + if (socket != null) { + socket.close(); + } + } catch (IOException ex) { + Log.w(TAG, "Failed closing socket", ex); + } + + Log.e(TAG, "Failed to connect to native daemon", + new IllegalStateException()); + SystemClock.sleep(5000); + } + + private void sendCommand(String command) { + sendCommand(command, null); + } + + /** + * Sends a command to the daemon with a single argument + * + * @param command The command to send to the daemon + * @param argument The argument to send with the command (or null) + */ + private void sendCommand(String command, String argument) { + synchronized (this) { + Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}"); + if (mOutputStream == null) { + Log.e(TAG, "No connection to daemon", new IllegalStateException()); + } else { + StringBuilder builder = new StringBuilder(command); + if (argument != null) { + builder.append(argument); + } + builder.append('\0'); + + try { + mOutputStream.write(builder.toString().getBytes()); + } catch (IOException ex) { + Log.e(TAG, "IOException in sendCommand", ex); + } + } + } + } + + public synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException { + sendCommand(cmd); + + ArrayList<String> response = new ArrayList<String>(); + boolean complete = false; + int code = -1; + + while (!complete) { + try { + String line = mResponseQueue.take(); +// Log.d(TAG, "Removed off queue -> " + line); + String[] tokens = line.split(" "); + try { + code = Integer.parseInt(tokens[0]); + } catch (NumberFormatException nfe) { + throw new IllegalStateException( + String.format("Invalid response from daemon (%s)", line)); + } + + if ((code >= 200) && (code < 600)) + complete = true; + response.add(line); + } catch (InterruptedException ex) { + Log.e(TAG, "InterruptedException"); + } + } + + if (code >= ResponseCode.FailedRangeStart && + code <= ResponseCode.FailedRangeEnd) { + throw new IllegalStateException(String.format( + "Command %s failed with code %d", + cmd, code)); + } + return response; + } +} diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index de3dcb01cee8..d5de1f0be1c1 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -330,6 +330,17 @@ public class WifiService extends IWifiManager.Stub { return false; } + /** + * Multiple calls to unregisterReceiver() cause exception and a system crash. + * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates + * disable wifi at the same time. + * Avoid doing a disable when the current Wifi state is UNKNOWN + * TODO: Handle driver load fail and supplicant lost as seperate states + */ + if (mWifiState == WIFI_STATE_UNKNOWN && !enable) { + return false; + } + setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid); if (enable) { diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index b95dd11046dd..4967ab81e5fc 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -18,6 +18,8 @@ package com.android.internal.telephony; import java.util.List; +import android.util.Log; + /** * {@hide} */ @@ -54,6 +56,8 @@ public abstract class Call { // merged, etc. protected boolean isGeneric = false; + protected final String LOG_TAG = "Call"; + /* Instance Methods */ /** Do not modify the List result!!! This list is not yours to keep @@ -235,4 +239,17 @@ public abstract class Call { public void setGeneric(boolean generic) { isGeneric = generic; } + + /** + * Hangup call if it is alive + */ + public void hangupIfAlive() { + if (getState().isAlive()) { + try { + hangup(); + } catch (CallStateException ex) { + Log.w(LOG_TAG, " hangupIfActive: caught " + ex); + } + } + } } diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index 6892998479f8..73836497dc4e 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -271,6 +271,13 @@ public abstract class ServiceStateTracker extends Handler { protected abstract void updateSpnDisplay(); protected abstract void setPowerStateToDesired(); + /** + * Clean up existing voice and data connection then turn off radio power. + * + * Hang up the existing voice calls to decrease call drop rate. + */ + protected abstract void powerOffRadioSafely(); + /** Cancel a pending (if any) pollState() operation */ protected void cancelPollState() { // This will effectively cancel the rest of the poll requests. diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index af3cbd5eb7e9..42feaa904b10 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -514,7 +514,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { synchronized(this) { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); - cm.setRadioPower(false, null); + hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; } } @@ -541,32 +541,42 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0); } - Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; - dcTracker.sendMessage(msg); - synchronized(this) { - if (!mPendingRadioPowerOffAfterDataOff) { - DataConnectionTracker.State currentState = dcTracker.getState(); - if (currentState != DataConnectionTracker.State.CONNECTED - && currentState != DataConnectionTracker.State.DISCONNECTING - && currentState != DataConnectionTracker.State.INITING) { - if (DBG) log("Data disconnected, turn off radio right away."); - cm.setRadioPower(false, null); - } - else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) { - if (DBG) { - log("Wait up to 30 sec for data to disconnect, then turn off radio."); - } - mPendingRadioPowerOffAfterDataOff = true; - } else { - Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); - cm.setRadioPower(false, null); + // If it's on and available and we want it off gracefully + powerOffRadioSafely(); + } // Otherwise, we're in the desired state + } + + @Override + protected void powerOffRadioSafely(){ + // clean data connection + DataConnectionTracker dcTracker = phone.mDataConnection; + + Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; + dcTracker.sendMessage(msg); + + synchronized(this) { + if (!mPendingRadioPowerOffAfterDataOff) { + DataConnectionTracker.State currentState = dcTracker.getState(); + if (currentState != DataConnectionTracker.State.CONNECTED + && currentState != DataConnectionTracker.State.DISCONNECTING + && currentState != DataConnectionTracker.State.INITING) { + if (DBG) log("Data disconnected, turn off radio right away."); + hangupAndPowerOff(); + } + else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) { + if (DBG) { + log("Wait up to 30 sec for data to disconnect, then turn off radio."); } + mPendingRadioPowerOffAfterDataOff = true; + } else { + Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); + hangupAndPowerOff(); } } - } // Otherwise, we're in the desired state + } } @Override @@ -1644,11 +1654,19 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("Process pending request to turn radio off."); removeMessages(EVENT_SET_RADIO_POWER_OFF); - cm.setRadioPower(false, null); + hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; return true; } return false; } } + + private void hangupAndPowerOff() { + // hang up all active voice calls + phone.mCT.ringingCall.hangupIfAlive(); + phone.mCT.backgroundCall.hangupIfAlive(); + phone.mCT.foregroundCall.hangupIfAlive(); + cm.setRadioPower(false, null); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 3f52eff59e67..6695ccbff2d9 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -808,7 +808,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); - phone.mCM.setRadioPower(false, null); + mGsmPhone.mSST.powerOffRadioSafely(); /* Note: no need to call setRadioPower(true). Assuming the desired * radio power state is still ON (as tracked by ServiceStateTracker), * ServiceStateTracker will call setRadioPower when it receives the diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index c2c89c016449..48e5c97b1131 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -518,26 +518,41 @@ final class GsmServiceStateTracker extends ServiceStateTracker { EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0); } - Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF; - dcTracker.sendMessage(msg); - - // poll data state up to 15 times, with a 100ms delay - // totaling 1.5 sec. Normal data disable action will finish in 100ms. - for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { - if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED - && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { - Log.d(LOG_TAG, "Data shutdown complete."); - break; - } - SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); - } - // If it's on and available and we want it off.. - cm.setRadioPower(false, null); + // If it's on and available and we want it off gracefully + powerOffRadioSafely(); } // Otherwise, we're in the desired state } + @Override + protected void powerOffRadioSafely() { + // clean data connection + DataConnectionTracker dcTracker = phone.mDataConnection; + Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF; + dcTracker.sendMessage(msg); + + // poll data state up to 15 times, with a 100ms delay + // totaling 1.5 sec. Normal data disable action will finish in 100ms. + for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { + Log.d(LOG_TAG, "Data shutdown complete."); + break; + } + SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); + } + + // hang up all active voice calls + if (phone.isInCall()) { + phone.mCT.ringingCall.hangupIfAlive(); + phone.mCT.backgroundCall.hangupIfAlive(); + phone.mCT.foregroundCall.hangupIfAlive(); + } + + cm.setRadioPower(false, null); + } + protected void updateSpnDisplay() { int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); String spn = phone.mSIMRecords.getServiceProviderName(); diff --git a/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java b/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java deleted file mode 100644 index 4b86add1c7d0..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests; - -import android.test.FrameworkTests; -import android.test.suitebuilder.TestSuiteBuilder; - -import junit.framework.TestSuite; - -public class AndroidTests extends TestSuite { - - public static TestSuite suite() { - TestSuiteBuilder suiteBuilder = new TestSuiteBuilder(AndroidTests.class); - TestSuite suite = suiteBuilder.includeAllPackagesUnderHere().build(); - - return suite; - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java deleted file mode 100644 index 5df499d1604d..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.CursorIndexOutOfBoundsException; -import android.database.DataSetObserver; -import android.database.DatabaseUtils; -import android.database.sqlite.SQLiteCursor; -import android.database.sqlite.SQLiteCursorDriver; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteQuery; -import android.database.sqlite.SQLiteStatement; -import android.os.Looper; -import android.test.PerformanceTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.Suppress; -import android.util.Log; - -import java.io.File; -import java.util.Arrays; -import java.util.Random; - -import junit.framework.TestCase; - -public class DatabaseCursorTest extends TestCase implements PerformanceTestCase { - - private static final String sString1 = "this is a test"; - private static final String sString2 = "and yet another test"; - private static final String sString3 = "this string is a little longer, but still a test"; - - private static final int CURRENT_DATABASE_VERSION = 42; - private SQLiteDatabase mDatabase; - private File mDatabaseFile; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db"); - if (mDatabaseFile.exists()) { - mDatabaseFile.delete(); - } - mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); - assertNotNull(mDatabase); - mDatabase.setVersion(CURRENT_DATABASE_VERSION); - } - - @Override - protected void tearDown() throws Exception { - mDatabase.close(); - mDatabaseFile.delete(); - super.tearDown(); - } - - public boolean isPerformanceOnly() { - return false; - } - - // These test can only be run once. - public int startPerformance(Intermediates intermediates) { - return 1; - } - - private void populateDefaultTable() { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); - - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); - } - - @MediumTest - public void testCursorUpdate() { - mDatabase.execSQL( - "CREATE TABLE test (_id INTEGER PRIMARY KEY, d INTEGER, s INTEGER);"); - for(int i = 0; i < 20; i++) { - mDatabase.execSQL("INSERT INTO test (d, s) VALUES (" + i + - "," + i%2 + ");"); - } - - Cursor c = mDatabase.query("test", null, "s = 0", null, null, null, null); - int dCol = c.getColumnIndexOrThrow("d"); - int sCol = c.getColumnIndexOrThrow("s"); - - int count = 0; - while (c.moveToNext()) { - assertTrue(c.updateInt(dCol, 3)); - count++; - } - assertEquals(10, count); - - assertTrue(c.commitUpdates()); - - assertTrue(c.requery()); - - count = 0; - while (c.moveToNext()) { - assertEquals(3, c.getInt(dCol)); - count++; - } - - assertEquals(10, count); - assertTrue(c.moveToFirst()); - assertTrue(c.deleteRow()); - assertEquals(9, c.getCount()); - c.close(); - } - - @MediumTest - public void testBlob() throws Exception { - // create table - mDatabase.execSQL( - "CREATE TABLE test (_id INTEGER PRIMARY KEY, s TEXT, d REAL, l INTEGER, b BLOB);"); - // insert blob - Object[] args = new Object[4]; - - byte[] blob = new byte[1000]; - byte value = 99; - Arrays.fill(blob, value); - args[3] = blob; - - String s = new String("text"); - args[0] = s; - Double d = 99.9; - args[1] = d; - Long l = (long)1000; - args[2] = l; - - String sql = "INSERT INTO test (s, d, l, b) VALUES (?,?,?,?)"; - mDatabase.execSQL(sql, args); - // use cursor to access blob - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - c.moveToNext(); - ContentValues cv = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(c, cv); - - int bCol = c.getColumnIndexOrThrow("b"); - int sCol = c.getColumnIndexOrThrow("s"); - int dCol = c.getColumnIndexOrThrow("d"); - int lCol = c.getColumnIndexOrThrow("l"); - byte[] cBlob = c.getBlob(bCol); - assertTrue(Arrays.equals(blob, cBlob)); - assertEquals(s, c.getString(sCol)); - assertEquals((double)d, c.getDouble(dCol)); - assertEquals((long)l, c.getLong(lCol)); - - // new byte[] - byte[] newblob = new byte[1000]; - value = 98; - Arrays.fill(blob, value); - - c.updateBlob(bCol, newblob); - cBlob = c.getBlob(bCol); - assertTrue(Arrays.equals(newblob, cBlob)); - - // commit - assertTrue(c.commitUpdates()); - assertTrue(c.requery()); - c.moveToNext(); - cBlob = c.getBlob(bCol); - assertTrue(Arrays.equals(newblob, cBlob)); - c.close(); - } - - @MediumTest - public void testRealColumns() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data REAL);"); - ContentValues values = new ContentValues(); - values.put("data", 42.11); - long id = mDatabase.insert("test", "data", values); - assertTrue(id > 0); - Cursor c = mDatabase.rawQuery("SELECT data FROM test", null); - assertNotNull(c); - assertTrue(c.moveToFirst()); - assertEquals(42.11, c.getDouble(0)); - c.close(); - } - - @MediumTest - public void testCursor1() throws Exception { - populateDefaultTable(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - - int dataColumn = c.getColumnIndexOrThrow("data"); - - // The cursor should ignore text before the last period when looking for a column. (This - // is a temporary hack in all implementations of getColumnIndex.) - int dataColumn2 = c.getColumnIndexOrThrow("junk.data"); - assertEquals(dataColumn, dataColumn2); - - assertSame(3, c.getCount()); - - assertTrue(c.isBeforeFirst()); - - try { - c.getInt(0); - fail("CursorIndexOutOfBoundsException expected"); - } catch (CursorIndexOutOfBoundsException ex) { - // expected - } - - c.moveToNext(); - assertEquals(1, c.getInt(0)); - - String s = c.getString(dataColumn); - assertEquals(sString1, s); - - c.moveToNext(); - s = c.getString(dataColumn); - assertEquals(sString2, s); - - c.moveToNext(); - s = c.getString(dataColumn); - assertEquals(sString3, s); - - c.moveToPosition(-1); - c.moveToNext(); - s = c.getString(dataColumn); - assertEquals(sString1, s); - - c.moveToPosition(2); - s = c.getString(dataColumn); - assertEquals(sString3, s); - - int i; - - for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) { - c.getInt(0); - } - - assertEquals(3, i); - - try { - c.getInt(0); - fail("CursorIndexOutOfBoundsException expected"); - } catch (CursorIndexOutOfBoundsException ex) { - // expected - } - c.close(); - } - - @MediumTest - public void testCursor2() throws Exception { - populateDefaultTable(); - - Cursor c = mDatabase.query("test", null, "_id > 1000", null, null, null, null); - assertEquals(0, c.getCount()); - assertTrue(c.isBeforeFirst()); - - try { - c.getInt(0); - fail("CursorIndexOutOfBoundsException expected"); - } catch (CursorIndexOutOfBoundsException ex) { - // expected - } - - int i; - for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) { - c.getInt(0); - } - assertEquals(0, i); - try { - c.getInt(0); - fail("CursorIndexOutOfBoundsException expected"); - } catch (CursorIndexOutOfBoundsException ex) { - // expected - } - c.close(); - } - - @MediumTest - public void testLargeField() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); - - StringBuilder sql = new StringBuilder(2100); - sql.append("INSERT INTO test (data) VALUES ('"); - Random random = new Random(System.currentTimeMillis()); - StringBuilder randomString = new StringBuilder(1979); - for (int i = 0; i < 1979; i++) { - randomString.append((random.nextInt() & 0xf) % 10); - } - sql.append(randomString); - sql.append("');"); - mDatabase.execSQL(sql.toString()); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - assertNotNull(c); - assertEquals(1, c.getCount()); - - assertTrue(c.moveToFirst()); - assertEquals(0, c.getPosition()); - String largeString = c.getString(c.getColumnIndexOrThrow("data")); - assertNotNull(largeString); - assertEquals(randomString.toString(), largeString); - c.close(); - } - - class TestObserver extends DataSetObserver { - int total; - SQLiteCursor c; - boolean quit = false; - public TestObserver(int total_, SQLiteCursor cursor) { - c = cursor; - total = total_; - } - - @Override - public void onChanged() { - int count = c.getCount(); - if (total == count) { - int i = 0; - while (c.moveToNext()) { - assertEquals(i, c.getInt(1)); - i++; - } - assertEquals(count, i); - quit = true; - Looper.myLooper().quit(); - } - } - - @Override - public void onInvalidated() { - } - } - - //@Large - @Suppress - public void testLoadingThreadDelayRegisterData() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); - - final int count = 505; - String sql = "INSERT INTO test (data) VALUES (?);"; - SQLiteStatement s = mDatabase.compileStatement(sql); - for (int i = 0; i < count; i++) { - s.bindLong(1, i); - s.execute(); - } - - int maxRead = 500; - int initialRead = 5; - SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", - null, initialRead, maxRead); - - TestObserver observer = new TestObserver(count, c); - c.getCount(); - c.registerDataSetObserver(observer); - if (!observer.quit) { - Looper.loop(); - } - c.close(); - } - - @LargeTest - public void testLoadingThread() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); - - final int count = 50000; - String sql = "INSERT INTO test (data) VALUES (?);"; - SQLiteStatement s = mDatabase.compileStatement(sql); - for (int i = 0; i < count; i++) { - s.bindLong(1, i); - s.execute(); - } - - int maxRead = 1000; - int initialRead = 5; - SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", - null, initialRead, maxRead); - - TestObserver observer = new TestObserver(count, c); - c.registerDataSetObserver(observer); - c.getCount(); - - Looper.loop(); - c.close(); - } - - @LargeTest - public void testLoadingThreadClose() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); - - final int count = 1000; - String sql = "INSERT INTO test (data) VALUES (?);"; - SQLiteStatement s = mDatabase.compileStatement(sql); - for (int i = 0; i < count; i++) { - s.bindLong(1, i); - s.execute(); - } - - int maxRead = 11; - int initialRead = 5; - SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", - null, initialRead, maxRead); - - TestObserver observer = new TestObserver(count, c); - c.registerDataSetObserver(observer); - c.getCount(); - c.close(); - } - - @LargeTest - public void testLoadingThreadDeactivate() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); - - final int count = 1000; - String sql = "INSERT INTO test (data) VALUES (?);"; - SQLiteStatement s = mDatabase.compileStatement(sql); - for (int i = 0; i < count; i++) { - s.bindLong(1, i); - s.execute(); - } - - int maxRead = 11; - int initialRead = 5; - SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;", - null, initialRead, maxRead); - - TestObserver observer = new TestObserver(count, c); - c.registerDataSetObserver(observer); - c.getCount(); - c.deactivate(); - c.close(); - } - - @LargeTest - public void testManyRowsLong() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);"); - - final int count = 36799; - for (int i = 0; i < count; i++) { - mDatabase.execSQL("INSERT INTO test (data) VALUES (" + i + ");"); - } - - Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null); - assertNotNull(c); - - int i = 0; - while (c.moveToNext()) { - assertEquals(i, c.getInt(0)); - i++; - } - assertEquals(count, i); - assertEquals(count, c.getCount()); - - Log.d("testManyRows", "count " + Integer.toString(i)); - c.close(); - } - - @LargeTest - public void testManyRowsTxt() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); - StringBuilder sql = new StringBuilder(2100); - sql.append("INSERT INTO test (data) VALUES ('"); - Random random = new Random(System.currentTimeMillis()); - StringBuilder randomString = new StringBuilder(1979); - for (int i = 0; i < 1979; i++) { - randomString.append((random.nextInt() & 0xf) % 10); - } - sql.append(randomString); - sql.append("');"); - - // if cursor window size changed, adjust this value too - final int count = 600; // more than two fillWindow needed - for (int i = 0; i < count; i++) { - mDatabase.execSQL(sql.toString()); - } - - Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null); - assertNotNull(c); - - int i = 0; - while (c.moveToNext()) { - assertEquals(randomString.toString(), c.getString(0)); - i++; - } - assertEquals(count, i); - assertEquals(count, c.getCount()); - c.close(); - } - - @LargeTest - public void testManyRowsTxtLong() throws Exception { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, txt TEXT, data INT);"); - - Random random = new Random(System.currentTimeMillis()); - StringBuilder randomString = new StringBuilder(1979); - for (int i = 0; i < 1979; i++) { - randomString.append((random.nextInt() & 0xf) % 10); - } - - // if cursor window size changed, adjust this value too - final int count = 600; - for (int i = 0; i < count; i++) { - StringBuilder sql = new StringBuilder(2100); - sql.append("INSERT INTO test (txt, data) VALUES ('"); - sql.append(randomString); - sql.append("','"); - sql.append(i); - sql.append("');"); - mDatabase.execSQL(sql.toString()); - } - - Cursor c = mDatabase.query("test", new String[]{"txt", "data"}, null, null, null, null, null); - assertNotNull(c); - - int i = 0; - while (c.moveToNext()) { - assertEquals(randomString.toString(), c.getString(0)); - assertEquals(i, c.getInt(1)); - i++; - } - assertEquals(count, i); - assertEquals(count, c.getCount()); - c.close(); - } - - @MediumTest - public void testRequery() throws Exception { - populateDefaultTable(); - - Cursor c = mDatabase.rawQuery("SELECT * FROM test", null); - assertNotNull(c); - assertEquals(3, c.getCount()); - c.deactivate(); - c.requery(); - assertEquals(3, c.getCount()); - c.close(); - } - - @MediumTest - public void testRequeryWithSelection() throws Exception { - populateDefaultTable(); - - Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = '" + sString1 + "'", - null); - assertNotNull(c); - assertEquals(1, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - c.deactivate(); - c.requery(); - assertEquals(1, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - c.close(); - } - - @MediumTest - public void testRequeryWithSelectionArgs() throws Exception { - populateDefaultTable(); - - Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = ?", - new String[]{sString1}); - assertNotNull(c); - assertEquals(1, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - c.deactivate(); - c.requery(); - assertEquals(1, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - c.close(); - } - - @MediumTest - public void testRequeryWithAlteredSelectionArgs() throws Exception { - /** - * Test the ability of a subclass of SQLiteCursor to change its query arguments. - */ - populateDefaultTable(); - - SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() { - public Cursor newCursor( - SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, - SQLiteQuery query) { - return new SQLiteCursor(db, masterQuery, editTable, query) { - @Override - public boolean requery() { - setSelectionArguments(new String[]{"2"}); - return super.requery(); - } - }; - } - }; - Cursor c = mDatabase.rawQueryWithFactory( - factory, "SELECT data FROM test WHERE _id <= ?", new String[]{"1"}, - null); - assertNotNull(c); - assertEquals(1, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - - // Our hacked requery() changes the query arguments in the cursor. - c.requery(); - - assertEquals(2, c.getCount()); - assertTrue(c.moveToFirst()); - assertEquals(sString1, c.getString(0)); - assertTrue(c.moveToNext()); - assertEquals(sString2, c.getString(0)); - - // Test that setting query args on a deactivated cursor also works. - c.deactivate(); - c.requery(); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java deleted file mode 100644 index 16ca59f51b83..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests; - -import android.database.Cursor; -import android.database.sqlite.SQLiteConstraintException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteDoneException; -import android.database.sqlite.SQLiteStatement; -import android.test.PerformanceTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import junit.framework.TestCase; - -import java.io.File; - -public class DatabaseStatementTest extends TestCase implements PerformanceTestCase { - - private static final String sString1 = "this is a test"; - private static final String sString2 = "and yet another test"; - private static final String sString3 = "this string is a little longer, but still a test"; - - private static final int CURRENT_DATABASE_VERSION = 42; - private SQLiteDatabase mDatabase; - private File mDatabaseFile; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db"); - if (mDatabaseFile.exists()) { - mDatabaseFile.delete(); - } - mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); - assertNotNull(mDatabase); - mDatabase.setVersion(CURRENT_DATABASE_VERSION); - } - - @Override - protected void tearDown() throws Exception { - mDatabase.close(); - mDatabaseFile.delete(); - super.tearDown(); - } - - public boolean isPerformanceOnly() { - return false; - } - - // These test can only be run once. - public int startPerformance(Intermediates intermediates) { - return 1; - } - - private void populateDefaultTable() { - mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); - - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');"); - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');"); - mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');"); - } - - @MediumTest - public void testExecuteStatement() throws Exception { - populateDefaultTable(); - SQLiteStatement statement = mDatabase.compileStatement("DELETE FROM test"); - statement.execute(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - assertEquals(0, c.getCount()); - c.deactivate(); - statement.close(); - } - - @MediumTest - public void testSimpleQuery() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);"); - mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');"); - SQLiteStatement statement1 = - mDatabase.compileStatement("SELECT num FROM test WHERE str = ?"); - SQLiteStatement statement2 = - mDatabase.compileStatement("SELECT str FROM test WHERE num = ?"); - - try { - statement1.bindString(1, "hello"); - long value = statement1.simpleQueryForLong(); - assertEquals(1234, value); - - statement1.bindString(1, "world"); - statement1.simpleQueryForLong(); - fail("shouldn't get here"); - } catch (SQLiteDoneException e) { - // expected - } - - try { - statement2.bindLong(1, 1234); - String value = statement1.simpleQueryForString(); - assertEquals("hello", value); - - statement2.bindLong(1, 5678); - statement1.simpleQueryForString(); - fail("shouldn't get here"); - } catch (SQLiteDoneException e) { - // expected - } - - statement1.close(); - statement2.close(); - } - - @MediumTest - public void testStatementLongBinding() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); - SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); - - for (int i = 0; i < 10; i++) { - statement.bindLong(1, i); - statement.execute(); - } - statement.close(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - int numCol = c.getColumnIndexOrThrow("num"); - c.moveToFirst(); - for (long i = 0; i < 10; i++) { - long num = c.getLong(numCol); - assertEquals(i, num); - c.moveToNext(); - } - c.close(); - } - - @MediumTest - public void testStatementStringBinding() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num TEXT);"); - SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); - - for (long i = 0; i < 10; i++) { - statement.bindString(1, Long.toHexString(i)); - statement.execute(); - } - statement.close(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - int numCol = c.getColumnIndexOrThrow("num"); - c.moveToFirst(); - for (long i = 0; i < 10; i++) { - String num = c.getString(numCol); - assertEquals(Long.toHexString(i), num); - c.moveToNext(); - } - c.close(); - } - - @MediumTest - public void testStatementClearBindings() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); - SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); - - for (long i = 0; i < 10; i++) { - statement.bindLong(1, i); - statement.clearBindings(); - statement.execute(); - } - statement.close(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); - int numCol = c.getColumnIndexOrThrow("num"); - assertTrue(c.moveToFirst()); - for (long i = 0; i < 10; i++) { - assertTrue(c.isNull(numCol)); - c.moveToNext(); - } - c.close(); - } - - @MediumTest - public void testSimpleStringBinding() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num TEXT, value TEXT);"); - String statement = "INSERT INTO test (num, value) VALUES (?,?)"; - - String[] args = new String[2]; - for (int i = 0; i < 2; i++) { - args[i] = Integer.toHexString(i); - } - - mDatabase.execSQL(statement, args); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - int numCol = c.getColumnIndexOrThrow("num"); - int valCol = c.getColumnIndexOrThrow("value"); - c.moveToFirst(); - String num = c.getString(numCol); - assertEquals(Integer.toHexString(0), num); - - String val = c.getString(valCol); - assertEquals(Integer.toHexString(1), val); - c.close(); - } - - @MediumTest - public void testStatementMultipleBindings() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); - SQLiteStatement statement = - mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); - - for (long i = 0; i < 10; i++) { - statement.bindLong(1, i); - statement.bindString(2, Long.toHexString(i)); - statement.execute(); - } - statement.close(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); - int numCol = c.getColumnIndexOrThrow("num"); - int strCol = c.getColumnIndexOrThrow("str"); - assertTrue(c.moveToFirst()); - for (long i = 0; i < 10; i++) { - long num = c.getLong(numCol); - String str = c.getString(strCol); - assertEquals(i, num); - assertEquals(Long.toHexString(i), str); - c.moveToNext(); - } - c.close(); - } - - private static class StatementTestThread extends Thread { - private SQLiteDatabase mDatabase; - private SQLiteStatement mStatement; - - public StatementTestThread(SQLiteDatabase db, SQLiteStatement statement) { - super(); - mDatabase = db; - mStatement = statement; - } - - @Override - public void run() { - mDatabase.beginTransaction(); - for (long i = 0; i < 10; i++) { - mStatement.bindLong(1, i); - mStatement.bindString(2, Long.toHexString(i)); - mStatement.execute(); - } - mDatabase.setTransactionSuccessful(); - mDatabase.endTransaction(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID"); - int numCol = c.getColumnIndexOrThrow("num"); - int strCol = c.getColumnIndexOrThrow("str"); - assertTrue(c.moveToFirst()); - for (long i = 0; i < 10; i++) { - long num = c.getLong(numCol); - String str = c.getString(strCol); - assertEquals(i, num); - assertEquals(Long.toHexString(i), str); - c.moveToNext(); - } - c.close(); - } - } - - @MediumTest - public void testStatementMultiThreaded() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);"); - SQLiteStatement statement = - mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)"); - - StatementTestThread thread = new StatementTestThread(mDatabase, statement); - thread.start(); - try { - thread.join(); - } finally { - statement.close(); - } - } - - @MediumTest - public void testStatementConstraint() throws Exception { - mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL);"); - SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)"); - - // Try to insert NULL, which violates the constraint - try { - statement.clearBindings(); - statement.execute(); - fail("expected exception not thrown"); - } catch (SQLiteConstraintException e) { - // expected - } - - // Make sure the statement can still be used - statement.bindLong(1, 1); - statement.execute(); - statement.close(); - - Cursor c = mDatabase.query("test", null, null, null, null, null, null); - int numCol = c.getColumnIndexOrThrow("num"); - c.moveToFirst(); - long num = c.getLong(numCol); - assertEquals(1, num); - c.close(); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java index a7a1400341dc..a288c73facdd 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java @@ -23,8 +23,6 @@ public class DatabaseTests { TestSuite suite = new TestSuite(DatabaseTests.class.getName()); suite.addTestSuite(DatabaseGeneralTest.class); - suite.addTestSuite(DatabaseCursorTest.class); - suite.addTestSuite(DatabaseStatementTest.class); suite.addTestSuite(DatabaseLocaleTest.class); suite.addTestSuite(CursorWindowTest.class); suite.addTestSuite(DatabaseLockTest.class); diff --git a/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java b/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java deleted file mode 100644 index 7252aa95fabf..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/NeighboringCellInfoTest.java +++ /dev/null @@ -1,79 +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 com.android.unit_tests; - -import android.os.Parcel; -import android.test.AndroidTestCase; -import android.telephony.NeighboringCellInfo; -import android.test. suitebuilder.annotation.SmallTest; - -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; -import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; - -public class NeighboringCellInfoTest extends AndroidTestCase { - @SmallTest - public void testConstructor() { - int rssi = 31; - NeighboringCellInfo nc; - - nc = new NeighboringCellInfo(rssi, "FFFFFFF", NETWORK_TYPE_EDGE); - assertEquals(NETWORK_TYPE_EDGE, nc.getNetworkType()); - assertEquals(rssi, nc.getRssi()); - assertEquals(0xfff, nc.getLac()); - assertEquals(0xffff, nc.getCid()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); - - nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UMTS); - assertEquals(NETWORK_TYPE_UMTS, nc.getNetworkType()); - assertEquals(rssi, nc.getRssi()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); - assertEquals(0x1ff, nc.getPsc()); - - nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UNKNOWN); - assertEquals(NETWORK_TYPE_UNKNOWN, nc.getNetworkType()); - assertEquals(rssi, nc.getRssi()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); - } - - @SmallTest - public void testParcel() { - int rssi = 20; - - NeighboringCellInfo nc = new NeighboringCellInfo(rssi, "12345678", NETWORK_TYPE_GPRS); - assertEquals(NETWORK_TYPE_GPRS, nc.getNetworkType()); - assertEquals(rssi, nc.getRssi()); - assertEquals(0x1234, nc.getLac()); - assertEquals(0x5678, nc.getCid()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); - - Parcel p = Parcel.obtain(); - p.setDataPosition(0); - nc.writeToParcel(p, 0); - - p.setDataPosition(0); - NeighboringCellInfo nw = new NeighboringCellInfo(p); - assertEquals(NETWORK_TYPE_GPRS, nw.getNetworkType()); - assertEquals(rssi, nw.getRssi()); - assertEquals(0x1234, nw.getLac()); - assertEquals(0x5678, nw.getCid()); - assertEquals(NeighboringCellInfo.UNKNOWN_CID, nw.getPsc()); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java deleted file mode 100644 index 4d5b5e778041..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.Resources; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.TypedValue; -import com.android.unit_tests.R; - -public class ArrayTest extends AndroidTestCase { - private Resources mResources; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); - } - - private void checkEntry(int resid, int index, Object res, Object expected) { - assertEquals("in resource 0x" + Integer.toHexString(resid) - + " at index " + index, expected, res); - } - - private void checkStringArray(int resid, String[] expected) { - String[] res = mResources.getStringArray(resid); - assertEquals(res.length, expected.length); - for (int i=0; i<expected.length; i++) { - checkEntry(resid, i, res[i], expected[i]); - } - } - - private void checkTextArray(int resid, String[] expected) { - CharSequence[] res = mResources.getTextArray(resid); - assertEquals(res.length, expected.length); - for (int i=0; i<expected.length; i++) { - checkEntry(resid, i, res[i], expected[i]); - } - } - - private void checkIntArray(int resid, int[] expected) { - int[] res = mResources.getIntArray(resid); - assertEquals(res.length, expected.length); - for (int i=0; i<expected.length; i++) { - assertEquals("in resource 0x" + Integer.toHexString(resid) - + " at index " + i, expected[i], res[i]); - } - } - - @SmallTest - public void testStrings() throws Exception { - checkStringArray(R.array.strings, new String[] {"zero", "1", "here"}); - checkTextArray(R.array.strings, new String[] {"zero", "1", "here"}); - checkStringArray(R.array.integers, new String[] {null, null, null}); - checkTextArray(R.array.integers, new String[] {null, null, null}); - } - - @SmallTest - public void testIntegers() throws Exception { - checkIntArray(R.array.strings, new int[] {0, 0, 0}); - checkIntArray(R.array.integers, new int[] {0, 1, 101}); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java deleted file mode 100644 index a065d7016af0..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.Context; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.WindowManager; -import com.android.unit_tests.R; - -import java.util.Locale; - -public class ConfigTest extends AndroidTestCase { - enum properties { - LANGUAGE, - COUNTRY, - MCC, - MNC, - TOUCHSCREEN, - KEYBOARD, - KEYBOARDHIDDEN, - NAVIGATION, - ORIENTATION, - WIDTH, - HEIGHT, - DENSITY - } - - private static void checkValue(Resources res, int resId, String expectedValue) { - try { - String actual = res.getString(resId); - assertNotNull("Returned wrong configuration-based simple value: expected <nothing>, got '" - + actual + "' from resource 0x" - + Integer.toHexString(resId), - expectedValue); - assertEquals("Returned wrong configuration-based simple value: expected '" - + expectedValue + "', got '" + actual + "' from resource 0x" - + Integer.toHexString(resId), - expectedValue, actual); - } catch (Resources.NotFoundException e) { - assertNull("Resource not found for configuration-based simple value: expecting \"" - + expectedValue + "\"", - expectedValue); - } - } - - private static void checkValue(Resources res, int resId, - int[] styleable, String[] expectedValues) { - Resources.Theme theme = res.newTheme(); - TypedArray sa = theme.obtainStyledAttributes(resId, styleable); - for (int i = 0; i < styleable.length; i++) { - String actual = sa.getString(i); - assertEquals("Returned wrong configuration-based style value: expected '" - + expectedValues[i] + "', got '" + actual + "' from attr " - + i + " of resource 0x" + Integer.toHexString(resId), - actual, expectedValues[i]); - } - sa.recycle(); - } - - class TotalConfig { - Configuration mConfig; - DisplayMetrics mMetrics; - - TotalConfig() { - mConfig = new Configuration(); - // don't rely on build settings - they may change - mConfig.locale = new Locale("en", "US"); - mConfig.mcc = 310; - mConfig.mnc = 001; // unused - mConfig.touchscreen = Configuration.TOUCHSCREEN_FINGER; - mConfig.keyboard = Configuration.KEYBOARD_QWERTY; - mConfig.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES; - mConfig.navigation = Configuration.NAVIGATION_TRACKBALL; - mConfig.orientation = Configuration.ORIENTATION_PORTRAIT; - - mMetrics = new DisplayMetrics(); - mMetrics.widthPixels = 200; - mMetrics.heightPixels = 320; - mMetrics.density = 1; - } - - void setProperty(properties p, int value) { - switch(p) { - case MCC: - mConfig.mcc = value; - break; - case MNC: - mConfig.mnc = value; - break; - case TOUCHSCREEN: - mConfig.touchscreen = value; - break; - case KEYBOARD: - mConfig.keyboard = value; - break; - case KEYBOARDHIDDEN: - mConfig.keyboardHidden = value; - break; - case NAVIGATION: - mConfig.navigation = value; - break; - case ORIENTATION: - mConfig.orientation = value; - break; - case WIDTH: - mMetrics.widthPixels = value; - break; - case HEIGHT: - mMetrics.heightPixels = value; - break; - case DENSITY: - // this is the ratio from the standard - - mMetrics.density = (((float)value)/((float)DisplayMetrics.DENSITY_DEFAULT)); - break; - default: - assert(false); - break; - } - } - - public void setProperty(properties p, String value) { - switch(p) { - case LANGUAGE: - String oldCountry = mConfig.locale.getCountry(); - mConfig.locale = new Locale(value, oldCountry); - break; - case COUNTRY: - String oldLanguage = mConfig.locale.getLanguage(); - mConfig.locale = new Locale(oldLanguage, value); - break; - default: - assert(false); - break; - } - } - - public Resources getResources() { - AssetManager assmgr = new AssetManager(); - assmgr.addAssetPath(mContext.getPackageResourcePath()); - return new Resources(assmgr, mMetrics, mConfig); - } - } - - private static void checkPair(Resources res, int[] notResIds, - int simpleRes, String simpleString, - int bagRes, String bagString) { - boolean willHave = true; - if (notResIds != null) { - for (int i : notResIds) { - if (i == simpleRes) { - willHave = false; - break; - } - } - } - checkValue(res, simpleRes, willHave ? simpleString : null); - checkValue(res, bagRes, R.styleable.TestConfig, - new String[]{willHave ? bagString : null}); - } - - @SmallTest - public void testAllConfigs() throws Exception { - /** - * Test a resource that contains a value for each possible single - * configuration value. - */ - TotalConfig config = new TotalConfig(); - Resources res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); - - config = new TotalConfig(); - config.setProperty(properties.LANGUAGE, "xx"); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple xx"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx"}); - - config = new TotalConfig(); - config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.COUNTRY, "YY"); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple xx-rYY"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx-rYY"}); - - config = new TotalConfig(); - config.setProperty(properties.MCC, 111); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mcc111"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mcc111"}); - - config = new TotalConfig(); - config.setProperty(properties.MNC, 222); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mnc222"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mnc222"}); - - config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_NOTOUCH); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple notouch"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag notouch"}); - - config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, Configuration.TOUCHSCREEN_STYLUS); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple stylus"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag stylus"}); - - config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_NOKEYS); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple nokeys"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag nokeys"}); - - config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 12key"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 12key"}); - - config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, Configuration.KEYBOARDHIDDEN_NO); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple keysexposed"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag keysexposed"}); - - config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_NONAV); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple nonav"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag nonav"}); - - config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_DPAD); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple dpad"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag dpad"}); - - config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, Configuration.NAVIGATION_WHEEL); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple wheel"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag wheel"}); - - config = new TotalConfig(); - config.setProperty(properties.HEIGHT, 480); - config.setProperty(properties.WIDTH, 320); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 480x320"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 480x320"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 240); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_LANDSCAPE); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple landscape"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag landscape"}); - - config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, Configuration.ORIENTATION_SQUARE); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple square"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag square"}); - } - - @MediumTest - public void testDensity() throws Exception { - // have 32, 240 and the default 160 content. - // rule is that closest wins, with down scaling (larger content) - // being twice as nice as upscaling. - // transition at H/2 * (-1 +/- sqrt(1+8L/H)) - // SO, X < 49 goes to 32 - // 49 >= X < 182 goes to 160 - // X >= 182 goes to 240 - TotalConfig config = new TotalConfig(); - config.setProperty(properties.DENSITY, 2); - Resources res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 32dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 32); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 32dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 48); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 32dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 49); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 150); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 181); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 182); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 239); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 490); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 240dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 240dpi"}); - } - -// TODO - add tests for special cases - ie, other key params seem ignored if -// nokeys is set - - @MediumTest - public void testCombinations() throws Exception { - /** - * Verify that proper strings are found for multiple-selectivity case - * (ie, a string set for locale and mcc is found only when both are - * true). - */ - TotalConfig config = new TotalConfig(); - config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.COUNTRY, "YY"); - config.setProperty(properties.MCC, 111); - Resources res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mcc111 xx-rYY"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mcc111 xx-rYY"}); - - config = new TotalConfig(); - config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.COUNTRY, "YY"); - config.setProperty(properties.MCC, 333); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple xx-rYY"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx-rYY"}); - - config = new TotalConfig(); - config.setProperty(properties.MNC, 333); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple default"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag default"}); - } - - @MediumTest - public void testPrecidence() throws Exception { - /** - * Verify that in cases of ties, the specific ordering is followed - */ - - /** - * Precidence order: mcc, mnc, locale, orientation, density, - * touchscreen, hidden, keyboard, navigation, width-height - */ - - /** - * verify mcc trumps mnc. Have 110-xx, 220-xx but no 110-220 - * so with is selected? Should be mcc110-xx. - */ - TotalConfig config = new TotalConfig(); - config.setProperty(properties.MCC, 110); - config.setProperty(properties.MNC, 220); - config.setProperty(properties.LANGUAGE, "xx"); - Resources res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mcc110 xx"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mcc110 xx"}); - - /* full A + B + C doesn't exist. Do we get A + C or B + C? - */ - config = new TotalConfig(); - config.setProperty(properties.MCC, 111); - config.setProperty(properties.MNC, 222); - config.setProperty(properties.LANGUAGE, "xx"); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mcc111 mnc222"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mcc111 mnc222"}); - - config = new TotalConfig(); - config.setProperty(properties.MNC, 222); - config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.ORIENTATION, - Configuration.ORIENTATION_SQUARE); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple mnc222 xx"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag mnc222 xx"}); - - config = new TotalConfig(); - config.setProperty(properties.LANGUAGE, "xx"); - config.setProperty(properties.ORIENTATION, - Configuration.ORIENTATION_SQUARE); - config.setProperty(properties.DENSITY, 32); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple xx square"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag xx square"}); - - config = new TotalConfig(); - config.setProperty(properties.ORIENTATION, - Configuration.ORIENTATION_SQUARE); - config.setProperty(properties.DENSITY, 32); - config.setProperty(properties.TOUCHSCREEN, - Configuration.TOUCHSCREEN_STYLUS); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple square 32dpi"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag square 32dpi"}); - - config = new TotalConfig(); - config.setProperty(properties.DENSITY, 32); - config.setProperty(properties.TOUCHSCREEN, - Configuration.TOUCHSCREEN_STYLUS); - config.setProperty(properties.KEYBOARDHIDDEN, - Configuration.KEYBOARDHIDDEN_NO); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 32dpi stylus"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 32dpi stylus"}); - - config = new TotalConfig(); - config.setProperty(properties.TOUCHSCREEN, - Configuration.TOUCHSCREEN_STYLUS); - config.setProperty(properties.KEYBOARDHIDDEN, - Configuration.KEYBOARDHIDDEN_NO); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple stylus keysexposed"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag stylus keysexposed"}); - - config = new TotalConfig(); - config.setProperty(properties.KEYBOARDHIDDEN, - Configuration.KEYBOARDHIDDEN_NO); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - config.setProperty(properties.NAVIGATION, - Configuration.NAVIGATION_DPAD); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple keysexposed 12key"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag keysexposed 12key"}); - - config = new TotalConfig(); - config.setProperty(properties.KEYBOARD, Configuration.KEYBOARD_12KEY); - config.setProperty(properties.NAVIGATION, - Configuration.NAVIGATION_DPAD); - config.setProperty(properties.HEIGHT, 63); - config.setProperty(properties.WIDTH, 57); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple 12key dpad"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag 12key dpad"}); - - config = new TotalConfig(); - config.setProperty(properties.NAVIGATION, - Configuration.NAVIGATION_DPAD); - config.setProperty(properties.HEIGHT, 640); - config.setProperty(properties.WIDTH, 400); - res = config.getResources(); - checkValue(res, R.configVarying.simple, "simple dpad"); - checkValue(res, R.configVarying.bag, - R.styleable.TestConfig, new String[]{"bag dpad"}); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java index 80318dcc6772..636660f8d48e 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java @@ -23,10 +23,6 @@ public class ContentTests { TestSuite suite = new TestSuite(ContentTests.class.getName()); suite.addTestSuite(AssetTest.class); - suite.addTestSuite(IntentFilterTest.class); - suite.addTest(ResourceTests.suite()); - suite.addTestSuite(PluralResourcesTest.class); - suite.addTestSuite(ConfigTest.class); return suite; } } diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java deleted file mode 100644 index 74a6b8de3d5b..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.Resources; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.TypedValue; -import com.android.unit_tests.R; - -public class FractionTest extends AndroidTestCase { - - private Resources mResources; - private final TypedValue mValue = new TypedValue(); - - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); - } - - @SmallTest - public void testFractions() throws Exception { - tryFraction(R.dimen.frac100perc, 1, 1, 1); - tryFraction(R.dimen.frac1perc, 1, 1, .01f); - tryFraction(R.dimen.fracp1perc, 1, 1, .001f); - tryFraction(R.dimen.fracp01perc, 1, 1, .0001f); - tryFraction(R.dimen.frac0perc, 1, 1, 0); - tryFraction(R.dimen.frac1p1perc, 1, 1, .011f); - tryFraction(R.dimen.frac100p1perc, 1, 1, 1.001f); - tryFraction(R.dimen.frac25510perc, 1, 1, 255.1f); - tryFraction(R.dimen.frac25610perc, 1, 1, 256.1f); - tryFraction(R.dimen.frac6553510perc, 1, 1, 65535.1f); - tryFraction(R.dimen.frac6553610perc, 1, 1, 65536.1f); - - tryFraction(R.dimen.frac100perc, 100, 1, 100); - tryFraction(R.dimen.frac1perc, 100, 1, .01f * 100); - tryFraction(R.dimen.fracp1perc, 100, 1, .001f * 100); - tryFraction(R.dimen.fracp01perc, 100, 1, .0001f * 100); - tryFraction(R.dimen.frac0perc, 100, 1, 0); - tryFraction(R.dimen.frac1p1perc, 100, 1, .011f * 100); - tryFraction(R.dimen.frac100p1perc, 100, 1, 1.001f * 100); - tryFraction(R.dimen.frac25510perc, 100, 1, 255.1f * 100); - tryFraction(R.dimen.frac25610perc, 100, 1, 256.1f * 100); - tryFraction(R.dimen.frac6553510perc, 100, 1, 65535.1f * 100); - tryFraction(R.dimen.frac6553610perc, 100, 1, 65536.1f * 100); - - tryFraction(R.dimen.frac100pperc, 100, 2, 2); - tryFraction(R.dimen.frac1pperc, 100, 2, .01f * 2); - tryFraction(R.dimen.fracp1pperc, 100, 2, .001f * 2); - tryFraction(R.dimen.fracp01pperc, 100, 2, .0001f * 2); - tryFraction(R.dimen.frac0pperc, 100, 2, 0); - tryFraction(R.dimen.frac1p1pperc, 100, 2, .011f * 2); - tryFraction(R.dimen.frac100p1pperc, 100, 2, 1.001f * 2); - tryFraction(R.dimen.frac25510pperc, 100, 2, 255.1f * 2); - tryFraction(R.dimen.frac25610pperc, 100, 2, 256.1f * 2); - tryFraction(R.dimen.frac6553510pperc, 100, 2, 65535.1f * 2); - tryFraction(R.dimen.frac6553610pperc, 100, 2, 65536.1f * 2); - } - - private void tryFraction(int resid, float base, float pbase, float expected) { - mResources.getValue(resid, mValue, true); - float res = mValue.getFraction(base, pbase); - float diff = Math.abs(expected - res); - float prec = expected * 1e-4f; - if (prec < 1e-5f) { - prec = 1e-5f; - } - //System.out.println( - // "Res 0x" + Integer.toHexString(resid) + ": got=" + res - // + ", expected=" + expected + ", diff=" + diff); - assertFalse("Expecting value " + expected + " got " + res - + ": in resource 0x" + Integer.toHexString(resid) - + " " + mValue, - diff > prec); - } -} - diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java deleted file mode 100644 index 0335b9d38798..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.IntentFilter; -import android.test.suitebuilder.annotation.SmallTest; -import static android.os.PatternMatcher.PATTERN_LITERAL; -import static android.os.PatternMatcher.PATTERN_PREFIX; -import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB; -import android.net.Uri; -import android.util.StringBuilderPrinter; -import junit.framework.TestCase; - -import java.util.HashSet; - -public class IntentFilterTest extends TestCase { - - public static class Match extends IntentFilter { - Match(String[] actions, String[] categories, String[] mimeTypes, - String[] schemes, String[] authorities, String[] ports) { - if (actions != null) { - for (int i = 0; i < actions.length; i++) { - addAction(actions[i]); - } - } - if (categories != null) { - for (int i = 0; i < categories.length; i++) { - addCategory(categories[i]); - } - } - if (mimeTypes != null) { - for (int i = 0; i < mimeTypes.length; i++) { - try { - addDataType(mimeTypes[i]); - } catch (IntentFilter.MalformedMimeTypeException e) { - throw new RuntimeException("Bad mime type", e); - } - } - } - if (schemes != null) { - for (int i = 0; i < schemes.length; i++) { - addDataScheme(schemes[i]); - } - } - if (authorities != null) { - for (int i = 0; i < authorities.length; i++) { - addDataAuthority(authorities[i], - ports != null ? ports[i] : null); - } - } - } - - Match(String[] actions, String[] categories, String[] mimeTypes, - String[] schemes, String[] authorities, String[] ports, - String[] paths, int[] pathTypes) { - this(actions, categories, mimeTypes, schemes, authorities, ports); - if (paths != null) { - for (int i = 0; i < paths.length; i++) { - addDataPath(paths[i], pathTypes[i]); - } - } - } - } - - public static class MatchCondition { - public final int result; - public final String action; - public final String mimeType; - public final Uri data; - public final String[] categories; - - public MatchCondition(int _result, String _action, String[] _categories, - String _mimeType, String _data) { - result = _result; - action = _action; - mimeType = _mimeType; - data = _data != null ? Uri.parse(_data) : null; - categories = _categories; - } - } - - public static void checkMatches(IntentFilter filter, - MatchCondition[] results) { - for (int i = 0; i < results.length; i++) { - MatchCondition mc = results[i]; - HashSet<String> categories = null; - if (mc.categories != null) { - for (int j = 0; j < mc.categories.length; j++) { - if (categories == null) { - categories = new HashSet<String>(); - } - categories.add(mc.categories[j]); - } - } - int result = filter.match(mc.action, mc.mimeType, - mc.data != null ? mc.data.getScheme() : null, mc.data, - categories, "test"); - if ( (result & IntentFilter.MATCH_CATEGORY_MASK) - != (mc.result & IntentFilter.MATCH_CATEGORY_MASK) ) { - StringBuilder msg = new StringBuilder(); - msg.append("Error matching against IntentFilter:\n"); - filter.dump(new StringBuilderPrinter(msg), " "); - msg.append("Match action: "); - msg.append(mc.action); - msg.append("\nMatch mimeType: "); - msg.append(mc.mimeType); - msg.append("\nMatch data: "); - msg.append(mc.data); - msg.append("\nMatch categories: "); - if (mc.categories != null) { - for (int j = 0; j < mc.categories.length; j++) { - if (j > 0) msg.append(", "); - msg.append(mc.categories[j]); - } - } - msg.append("\nExpected result: 0x"); - msg.append(Integer.toHexString(mc.result)); - msg.append(", got result: 0x"); - msg.append(Integer.toHexString(result)); - throw new RuntimeException(msg.toString()); - } - } - } - - @SmallTest - public void testActions() throws Exception { - IntentFilter filter = new Match( - new String[]{"action1"}, null, null, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1", - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action2", - null, null, null), - }); - - filter = new Match( - new String[]{"action1", "action2"}, - null, null, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1", - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action2", - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action3", - null, null, null), - }); - } - - @SmallTest - public void testCategories() throws Exception { - IntentFilter filter = new Match( - null, new String[]{"category1"}, null, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - new String[]{"category1"}, null, null), - new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, - new String[]{"category2"}, null, null), - new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, - new String[]{"category1", "category2"}, null, null), - }); - - filter = new Match( - null, new String[]{"category1", "category2"}, null, null, - null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - new String[]{"category1"}, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - new String[]{"category2"}, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null, - new String[]{"category1", "category2"}, null, null), - new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, - new String[]{"category3"}, null, null), - new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null, - new String[]{"category1", "category2", "category3"}, - null, null), - }); - } - - @SmallTest - public void testMimeTypes() throws Exception { - IntentFilter filter = new Match( - null, null, new String[]{"which1/what1"}, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what1", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "*/*", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which2/what2", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which2/*", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which1/what2", null), - }); - - filter = new Match(null, null, - new String[]{"which1/what1", "which2/what2"}, null, null, - null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what1", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "*/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which2/what2", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which2/*", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which1/what2", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which3/what3", null), - }); - - filter = new Match(null, null, - new String[]{"which1/*"}, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what1", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "*/*", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which2/what2", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which2/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what2", null), - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null, - "which3/what3", null), - }); - - filter = new Match(null, null, - new String[]{"*/*"}, null, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what1", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "*/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which2/what2", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which2/*", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which1/what2", null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null, - "which3/what3", null), - }); - } - - @SmallTest - public void testSchemes() throws Exception { - IntentFilter filter = new Match(null, null, null, - new String[]{"scheme1"}, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, - null, null, "scheme1:foo"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme2:foo"), - }); - - filter = new Match(null, null, null, - new String[]{"scheme1", "scheme2"}, null, null); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, - null, null, "scheme1:foo"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null, - null, null, "scheme2:foo"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme3:foo"), - }); - } - - @SmallTest - public void testAuthorities() throws Exception { - IntentFilter filter = new Match(null, null, null, - new String[]{"scheme1"}, - new String[]{"authority1"}, new String[]{null}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1:foo"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, - null, null, "scheme1://authority1/"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority2/"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, - null, null, "scheme1://authority1:100/"), - }); - - filter = new Match(null, null, null, new String[]{"scheme1"}, - new String[]{"authority1"}, new String[]{"100"}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1:foo"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority1/"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority2/"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null, - null, null, "scheme1://authority1:100/"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority1:200/"), - }); - - filter = new Match(null, null, null, new String[]{"scheme1"}, - new String[]{"authority1", "authority2"}, - new String[]{"100", null}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1:foo"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority1/"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null, - null, null, "scheme1://authority2/"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null, - null, null, "scheme1://authority1:100/"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme1://authority1:200/"), - }); - } - - @SmallTest - public void testPaths() throws Exception { - IntentFilter filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/literal1", "/2literal"}, - new int[]{PATTERN_LITERAL, PATTERN_LITERAL}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/literal1"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/2literal"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/literal"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/literal12"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/literal1", "/2literal"}, - new int[]{PATTERN_PREFIX, PATTERN_PREFIX}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/literal1"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/2literal"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/literal"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/literal12"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/.*"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/literal1"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{".*"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/literal1"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a1*b"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a1b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a11b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a2b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a1bc"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a1*"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a1"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a11"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a1b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a11"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a2"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a\\.*b"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a..b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a2b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a.bc"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a.*b"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.1b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a2b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a.bc"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a.*"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.1b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a2b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.bc"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a.\\*b"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.*b"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a1*b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a2b"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a.bc"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/"), - }); - filter = new Match(null, null, null, - new String[]{"scheme"}, new String[]{"authority"}, null, - new String[]{"/a.\\*"}, - new int[]{PATTERN_SIMPLE_GLOB}); - checkMatches(filter, new MatchCondition[]{ - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, null), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/ab"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a.*"), - new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null, - null, null, "scheme://authority/a1*"), - new MatchCondition(IntentFilter.NO_MATCH_DATA, null, - null, null, "scheme://authority/a1b"), - }); - } - -} - diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java deleted file mode 100644 index c3d1478e8f63..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.TypedValue; -import android.util.Log; -import com.android.unit_tests.R; - -import junit.framework.Assert; - -import java.util.Locale; - -public class PluralResourcesTest extends AndroidTestCase { - private static final String TAG = "PluralResourcesTest"; - - private Resources mResources; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); - } - - Resources resourcesForLanguage(String lang) { - Configuration config = new Configuration(); - config.updateFrom(mResources.getConfiguration()); - config.locale = new Locale(lang); - return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config); - } - - @SmallTest - public void testPlurals() throws Exception { - CharSequence cs; - Resources res = resourcesForLanguage("en"); - - cs = res.getQuantityText(R.plurals.plurals_test, 0); - Log.d(TAG, "english 0 cs=" + cs); - Assert.assertEquals(cs.toString(), "Some dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 1); - Log.d(TAG, "english 1 cs=" + cs); - Assert.assertEquals(cs.toString(), "A dog"); - - cs = res.getQuantityText(R.plurals.plurals_test, 2); - Assert.assertEquals(cs.toString(), "Some dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 5); - Assert.assertEquals(cs.toString(), "Some dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 500); - Assert.assertEquals(cs.toString(), "Some dogs"); - } - - @SmallTest - public void testCzech() throws Exception { - CharSequence cs; - Resources res = resourcesForLanguage("cs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 0); - Log.d(TAG, "czech 0 cs=" + cs); - Assert.assertEquals(cs.toString(), "Some Czech dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 1); - Log.d(TAG, "czech 1 cs=" + cs); - Assert.assertEquals(cs.toString(), "A Czech dog"); - - cs = res.getQuantityText(R.plurals.plurals_test, 2); - Log.d(TAG, "czech 2 cs=" + cs); - Assert.assertEquals(cs.toString(), "Few Czech dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 5); - Assert.assertEquals(cs.toString(), "Some Czech dogs"); - - cs = res.getQuantityText(R.plurals.plurals_test, 500); - Assert.assertEquals(cs.toString(), "Some Czech dogs"); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java deleted file mode 100644 index 44098cc5edcb..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.TypedValue; -import com.android.unit_tests.R; - -public class PrimitiveTest extends AndroidTestCase { - private Resources mResources; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); - } - - private void tryEnum(int resid, int expected) { - TypedArray sa = - mContext.obtainStyledAttributes(resid, R.styleable.EnumStyle); - int value = sa.getInt(R.styleable.EnumStyle_testEnum, -1); - sa.recycle(); - - assertEquals("Expecting value " + expected + " got " + value - + ": in resource 0x" + Integer.toHexString(resid), - expected, value); - } - - @SmallTest - public void testEnum() throws Exception { - tryEnum(R.style.TestEnum1, 1); - tryEnum(R.style.TestEnum2, 2); - tryEnum(R.style.TestEnum10, 10); - tryEnum(R.style.TestEnum1_EmptyInherit, 1); - } - - private void tryFlag(int resid, int expected) { - TypedArray sa = - mContext.obtainStyledAttributes(resid, R.styleable.FlagStyle); - int value = sa.getInt(R.styleable.FlagStyle_testFlags, -1); - sa.recycle(); - - assertEquals("Expecting value " + expected + " got " + value - + ": in resource 0x" + Integer.toHexString(resid), - expected, value); - } - - @SmallTest - public void testFlags() throws Exception { - tryFlag(R.style.TestFlag1, 0x1); - tryFlag(R.style.TestFlag2, 0x2); - tryFlag(R.style.TestFlag31, 0x40000000); - tryFlag(R.style.TestFlag1And2, 0x3); - tryFlag(R.style.TestFlag1And2And31, 0x40000003); - } - - private void tryBoolean(int resid, boolean expected) { - TypedValue v = new TypedValue(); - mContext.getResources().getValue(resid, v, true); - assertEquals(TypedValue.TYPE_INT_BOOLEAN, v.type); - assertEquals("Expecting boolean value " + expected + " got " + v - + " from TypedValue: in resource 0x" + Integer.toHexString(resid), - expected, v.data != 0); - assertEquals("Expecting boolean value " + expected + " got " + v - + " from getBoolean(): in resource 0x" + Integer.toHexString(resid), - expected, mContext.getResources().getBoolean(resid)); - } - - @SmallTest - public void testBoolean() throws Exception { - tryBoolean(R.bool.trueRes, true); - tryBoolean(R.bool.falseRes, false); - } - - private void tryString(int resid, String expected) { - TypedValue v = new TypedValue(); - mContext.getResources().getValue(resid, v, true); - assertEquals(TypedValue.TYPE_STRING, v.type); - assertEquals("Expecting string value " + expected + " got " + v - + ": in resource 0x" + Integer.toHexString(resid), - expected, v.string); - } - - @SmallTest - public void testStringCoerce() throws Exception { - tryString(R.string.coerceIntegerToString, "100"); - tryString(R.string.coerceBooleanToString, "true"); - tryString(R.string.coerceColorToString, "#fff"); - tryString(R.string.coerceFloatToString, "100.0"); - tryString(R.string.coerceDimensionToString, "100px"); - tryString(R.string.coerceFractionToString, "100%"); - } - - private static void checkString(int resid, String actual, String expected) { - assertEquals("Expecting string value \"" + expected + "\" got \"" - + actual + "\" in resources 0x" + Integer.toHexString(resid), - expected, actual); - } - - @SmallTest - public void testFormattedString() throws Exception { - // Make sure the regular one doesn't format anything - checkString(R.string.formattedStringNone, - mResources.getString(R.string.formattedStringNone), - "Format[]"); - checkString(R.string.formattedStringOne, - mResources.getString(R.string.formattedStringOne), - "Format[%d]"); - checkString(R.string.formattedStringTwo, - mResources.getString(R.string.formattedStringTwo), - "Format[%3$d,%2$s]"); - // Make sure the formatted one works - checkString(R.string.formattedStringNone, - mResources.getString(R.string.formattedStringNone), - "Format[]"); - checkString(R.string.formattedStringOne, - mResources.getString(R.string.formattedStringOne, 42), - "Format[42]"); - checkString(R.string.formattedStringTwo, - mResources.getString(R.string.formattedStringTwo, "unused", "hi", 43), - "Format[43,hi]"); - } -} - diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java deleted file mode 100644 index 1786dc46b89f..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.Resources; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import com.android.unit_tests.R; - -import java.io.InputStream; - -public class RawResourceTest extends AndroidTestCase { - private Resources mResources; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mResources = mContext.getResources(); - } - - @SmallTest - public void testReadToEnd() throws Exception { - InputStream is = mResources.openRawResource(R.raw.text); - AssetTest.verifyTextAsset(is); - } -} diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java deleted file mode 100644 index 2a56243cfb0e..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import android.content.res.Resources; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.unit_tests.R; - -public class ResourceNameTest extends AndroidTestCase { - - @SmallTest - public void testGetResourceName() { - Resources res = mContext.getResources(); - - String fullName = res.getResourceName(R.configVarying.simple); - assertEquals("com.android.unit_tests:configVarying/simple", fullName); - - String packageName = res.getResourcePackageName(R.configVarying.simple); - assertEquals("com.android.unit_tests", packageName); - - String typeName = res.getResourceTypeName(R.configVarying.simple); - assertEquals("configVarying", typeName); - - String entryName = res.getResourceEntryName(R.configVarying.simple); - assertEquals("simple", entryName); - } - - @SmallTest - public void testGetResourceIdentifier() { - Resources res = mContext.getResources(); - int resid = res.getIdentifier( - "com.android.unit_tests:configVarying/simple", - null, null); - assertEquals(R.configVarying.simple, resid); - - resid = res.getIdentifier("configVarying/simple", null, - "com.android.unit_tests"); - assertEquals(R.configVarying.simple, resid); - - resid = res.getIdentifier("simple", "configVarying", - "com.android.unit_tests"); - assertEquals(R.configVarying.simple, resid); - } -} - diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java deleted file mode 100644 index 943941e517a4..000000000000 --- a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.unit_tests.content; - -import junit.framework.TestSuite; - -public class ResourceTests { - public static TestSuite suite() { - TestSuite suite = new TestSuite(ResourceTests.class.getName()); - - suite.addTestSuite(FractionTest.class); - suite.addTestSuite(PrimitiveTest.class); - suite.addTestSuite(ArrayTest.class); - suite.addTestSuite(ConfigTest.class); - suite.addTestSuite(RawResourceTest.class); - suite.addTestSuite(ResourceNameTest.class); - return suite; - } -} diff --git a/tests/CoreTests/android/core/CoreTests.java b/tests/CoreTests/android/core/CoreTests.java index e4f835c05737..442fe0f943ad 100644 --- a/tests/CoreTests/android/core/CoreTests.java +++ b/tests/CoreTests/android/core/CoreTests.java @@ -59,7 +59,6 @@ public class CoreTests extends TestSuite { suite.addTestSuite(LocationManagerProximityTest.class); suite.addTestSuite(AndroidTestRunnerTest.class); suite.addTestSuite(InstrumentationTestRunnerTest.class); - suite.addTestSuite(CookieTest.class); return suite; } diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java deleted file mode 100644 index 5c5a6a825658..000000000000 --- a/tests/CoreTests/android/webkit/CookieTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2008 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.webkit; - -import android.content.Context; -import android.test.AndroidTestCase; -import android.util.Log; -import android.webkit.CookieManager; -import android.webkit.CookieSyncManager; - -public class CookieTest extends AndroidTestCase { - - /** - * To run these tests: $ mmm frameworks/base/tests/CoreTests/android && adb - * remount && adb sync $ adb shell am instrument -w \ -e class - * android.webkit.CookieTest \ - * android.core/android.test.InstrumentationTestRunner - */ - - private CookieManager mCookieManager; - - @Override - public void setContext(Context context) { - assertTrue(mContext == null); - super.setContext(context); - CookieSyncManager.createInstance(context); - mCookieManager = CookieManager.getInstance(); - mCookieManager.removeAllCookie(); - } - - public void testParse() { - mCookieManager.removeAllCookie(); - String url = "http://www.foo.com"; - - // basic - mCookieManager.setCookie(url, "a=b"); - String cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b")); - - // quoted - mCookieManager.setCookie(url, "c=\"d;\""); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b; c=\"d;\"")); - - // empty - mCookieManager.setCookie(url, "; path=/"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b; c=\"d;\"")); - } - - public void testDomain() { - mCookieManager.removeAllCookie(); - String url = "http://www.foo.com"; - - // basic - mCookieManager.setCookie(url, "a=b"); - String cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b")); - - // no cross domain cookie - cookie = mCookieManager.getCookie("http://bar.com"); - assertTrue(cookie == null); - - // more than one cookie - mCookieManager.setCookie(url, "c=d; domain=.foo.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b; c=d")); - - // host cookie should not be accessible from a sub-domain. - cookie = mCookieManager.getCookie("http://bar.www.foo.com"); - assertTrue(cookie.equals("c=d")); - - // test setting a domain= that doesn't start w/ a dot, should - // treat it as a domain cookie, as if there was a pre-pended dot. - mCookieManager.setCookie(url, "e=f; domain=www.foo.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=b; c=d; e=f")); - cookie = mCookieManager.getCookie("http://sub.www.foo.com"); - assertTrue(cookie.equals("c=d; e=f")); - cookie = mCookieManager.getCookie("http://foo.com"); - assertTrue(cookie.equals("c=d")); - } - - public void testSubDomain() { - mCookieManager.removeAllCookie(); - String url_abcd = "http://a.b.c.d.com"; - String url_bcd = "http://b.c.d.com"; - String url_cd = "http://c.d.com"; - String url_d = "http://d.com"; - - mCookieManager.setCookie(url_abcd, "a=1; domain=.a.b.c.d.com"); - mCookieManager.setCookie(url_abcd, "b=2; domain=.b.c.d.com"); - mCookieManager.setCookie(url_abcd, "c=3; domain=.c.d.com"); - mCookieManager.setCookie(url_abcd, "d=4; domain=.d.com"); - - String cookie = mCookieManager.getCookie(url_abcd); - assertTrue(cookie.equals("a=1; b=2; c=3; d=4")); - cookie = mCookieManager.getCookie(url_bcd); - assertTrue(cookie.equals("b=2; c=3; d=4")); - cookie = mCookieManager.getCookie(url_cd); - assertTrue(cookie.equals("c=3; d=4")); - cookie = mCookieManager.getCookie(url_d); - assertTrue(cookie.equals("d=4")); - - // check that the same cookie can exist on different sub-domains. - mCookieManager.setCookie(url_bcd, "x=bcd; domain=.b.c.d.com"); - mCookieManager.setCookie(url_bcd, "x=cd; domain=.c.d.com"); - cookie = mCookieManager.getCookie(url_bcd); - assertTrue(cookie.equals("b=2; c=3; d=4; x=bcd; x=cd")); - cookie = mCookieManager.getCookie(url_cd); - assertTrue(cookie.equals("c=3; d=4; x=cd")); - } - - public void testInvalidDomain() { - mCookieManager.removeAllCookie(); - String url = "http://foo.bar.com"; - - mCookieManager.setCookie(url, "a=1; domain=.yo.foo.bar.com"); - String cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "b=2; domain=.foo.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "c=3; domain=.bar.foo.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "d=4; domain=.foo.bar.com.net"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "e=5; domain=.ar.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "f=6; domain=.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "g=7; domain=.co.uk"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "h=8; domain=.foo.bar.com.com"); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - } - - public void testPath() { - mCookieManager.removeAllCookie(); - String url = "http://www.foo.com"; - - mCookieManager.setCookie(url, "a=b; path=/wee"); - String cookie = mCookieManager.getCookie(url + "/wee"); - assertTrue(cookie.equals("a=b")); - cookie = mCookieManager.getCookie(url + "/wee/"); - assertTrue(cookie.equals("a=b")); - cookie = mCookieManager.getCookie(url + "/wee/hee"); - assertTrue(cookie.equals("a=b")); - cookie = mCookieManager.getCookie(url + "/wee/hee/more"); - assertTrue(cookie.equals("a=b")); - cookie = mCookieManager.getCookie(url + "/weehee"); - assertTrue(cookie == null); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie == null); - - mCookieManager.setCookie(url, "a=c; path="); - cookie = mCookieManager.getCookie(url + "/wee"); - assertTrue(cookie.equals("a=b; a=c")); - cookie = mCookieManager.getCookie(url); - assertTrue(cookie.equals("a=c")); - - mCookieManager.setCookie(url, "a=d"); - cookie = mCookieManager.getCookie(url + "/wee"); - assertTrue(cookie.equals("a=b; a=d")); - } -} diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java deleted file mode 100644 index 49b5106cf7a5..000000000000 --- a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.frameworktest.expandablelistview; - -import android.test.ActivityInstrumentationTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; -import android.view.KeyEvent; -import android.widget.ExpandableListView; - -import com.android.frameworktest.expandablelistview.ExpandableListWithHeaders; -import com.android.frameworktest.util.ListUtil; - -public class ExpandableListWithHeadersTest extends ActivityInstrumentationTestCase<ExpandableListWithHeaders> { - private ExpandableListView mExpandableListView; - private ListUtil mListUtil; - - public ExpandableListWithHeadersTest() { - super("com.android.frameworktest", - ExpandableListWithHeaders.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - mExpandableListView = getActivity().getExpandableListView(); - mListUtil = new ListUtil(mExpandableListView, getInstrumentation()); - } - - @MediumTest - public void testPreconditions() { - assertNotNull(mExpandableListView); - } - - @MediumTest - public void testExpandOnFirstPosition() { - // Should be a header, and hence the first group should NOT have expanded - mListUtil.arrowScrollToSelectedPosition(0); - sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); - getInstrumentation().waitForIdleSync(); - assertFalse(mExpandableListView.isGroupExpanded(0)); - } - - @LargeTest - public void testExpandOnFirstGroup() { - mListUtil.arrowScrollToSelectedPosition(getActivity().getNumOfHeadersAndFooters()); - sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); - getInstrumentation().waitForIdleSync(); - assertTrue(mExpandableListView.isGroupExpanded(0)); - } -} diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java deleted file mode 100644 index 3dcb2525500e..000000000000 --- a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.frameworktest.view; - -import android.os.Parcel; -import android.test.ActivityInstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.view.InflateException; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RemoteViews; - -import com.android.frameworktest.R; -import com.android.frameworktest.view.RemoteViewsActivity; - -public class RemoteViewsActivityTest extends ActivityInstrumentationTestCase<RemoteViewsActivity> { - public RemoteViewsActivityTest() { - super("com.android.frameworktest", RemoteViewsActivity.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - } - - @MediumTest - public void testGood() throws Exception { - final RemoteViewsActivity activity = getActivity(); - - RemoteViews orig = new RemoteViews("com.android.frameworktest", - R.layout.remote_view_test_good); - Parcel p = Parcel.obtain(); - orig.writeToParcel(p, 0); - p.setDataPosition(0); - - RemoteViews r = RemoteViews.CREATOR.createFromParcel(p); - - ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent); - - View result = r.apply(activity, parent); - - p.recycle(); - - assertTrue("LinearLayout not inflated", result.findViewById(R.id.linear) != null); - assertTrue("TextView not inflated", result.findViewById(R.id.text) != null); - assertTrue("ImageView not inflated", result.findViewById(R.id.image) != null); - assertTrue("FrameLayout not inflated", result.findViewById(R.id.frame) != null); - assertTrue("RelateiveLayout not inflated", result.findViewById(R.id.relative) != null); - assertTrue("AbsoluteLayout not inflated", result.findViewById(R.id.absolute) != null); - assertTrue("ProgressBar not inflated", result.findViewById(R.id.progress) != null); - assertTrue("ImageButton not inflated", result.findViewById(R.id.image_button) != null); - assertTrue("Button not inflated", result.findViewById(R.id.button) != null); - } - - @MediumTest - public void testDerivedClass() throws Exception { - final RemoteViewsActivity activity = getActivity(); - - RemoteViews orig = new RemoteViews("com.android.frameworktest", - R.layout.remote_view_test_bad_1); - Parcel p = Parcel.obtain(); - orig.writeToParcel(p, 0); - p.setDataPosition(0); - - RemoteViews r = RemoteViews.CREATOR.createFromParcel(p); - - ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent); - - boolean exceptionThrown = false; - View result = null; - - try { - result = r.apply(activity, parent); - } catch (InflateException e) { - exceptionThrown = true; - } - - p.recycle(); - - assertTrue("Derived class (EditText) allowed to be inflated", exceptionThrown); - assertNull("Derived class (EditText) allowed to be inflated", result); - } - - @MediumTest - public void testWebView() throws Exception { - final RemoteViewsActivity activity = getActivity(); - - RemoteViews orig = new RemoteViews("com.android.frameworktest", - R.layout.remote_view_test_bad_2); - Parcel p = Parcel.obtain(); - orig.writeToParcel(p, 0); - p.setDataPosition(0); - - RemoteViews r = RemoteViews.CREATOR.createFromParcel(p); - - ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent); - - boolean exceptionThrown = false; - View result = null; - - try { - result = r.apply(activity, parent); - } catch (InflateException e) { - exceptionThrown = true; - } - - p.recycle(); - - assertTrue("WebView allowed to be inflated", exceptionThrown); - assertNull("WebView allowed to be inflated", result); - } -} diff --git a/tests/TransformTest/Android.mk b/tests/TransformTest/Android.mk new file mode 100644 index 000000000000..2d3637da569a --- /dev/null +++ b/tests/TransformTest/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := TransformTest + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/TransformTest/AndroidManifest.xml b/tests/TransformTest/AndroidManifest.xml new file mode 100644 index 000000000000..5c9995f25ec6 --- /dev/null +++ b/tests/TransformTest/AndroidManifest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.android.test.transform"> + <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7" /> + <application android:label="TransformTest"> + <activity android:name="TransformTestActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/TransformTest/res/drawable/logo.png b/tests/TransformTest/res/drawable/logo.png Binary files differnew file mode 100644 index 000000000000..4d717a86143d --- /dev/null +++ b/tests/TransformTest/res/drawable/logo.png diff --git a/tests/TransformTest/res/values/strings.xml b/tests/TransformTest/res/values/strings.xml new file mode 100644 index 000000000000..a0eb81ff11f6 --- /dev/null +++ b/tests/TransformTest/res/values/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2007 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. +--> + +<resources> + <string name="act_title">TransformTest</string> +</resources> diff --git a/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java b/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java new file mode 100644 index 000000000000..52286d188bdb --- /dev/null +++ b/tests/TransformTest/src/com/google/android/test/transform/TransformTestActivity.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.transform; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.TransformGestureDetector; +import android.view.View; +import android.widget.LinearLayout; + +public class TransformTestActivity extends Activity { + public TransformTestActivity() { + super(); + init(false); + } + + public TransformTestActivity(boolean noCompat) { + super(); + init(noCompat); + } + + public void init(boolean noCompat) { + + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final LayoutInflater li = (LayoutInflater)getSystemService( + LAYOUT_INFLATER_SERVICE); + + this.setTitle(R.string.act_title); + LinearLayout root = new LinearLayout(this); + root.setOrientation(LinearLayout.VERTICAL); + + TransformView view = new TransformView(getApplicationContext()); + Drawable drawable = getResources().getDrawable(R.drawable.logo); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicWidth()); + view.setDrawable(drawable); + + root.addView(view); + setContentView(root); + } + + private class TransformView extends View { + private Drawable mDrawable; + private float mPosX; + private float mPosY; + private float mScale = 1.f; + private Matrix mMatrix; + private TransformGestureDetector mDetector; + + private class Listener implements TransformGestureDetector.OnTransformGestureListener { + + public boolean onTransform(TransformGestureDetector detector) { + Log.d("ttest", "Translation: (" + detector.getTranslateX() + + ", " + detector.getTranslateY() + ")"); + float scale = detector.getScaleFactor(); + Log.d("ttest", "Scale: " + scale); + if (mScale * scale > 0.1f) { + if (mScale * scale < 10.f) { + mScale *= scale; + } else { + mScale = 10.f; + } + } else { + mScale = 0.1f; + } + + mPosX += detector.getTranslateX(); + mPosY += detector.getTranslateY(); + + Log.d("ttest", "mScale: " + mScale + " mPos: (" + mPosX + ", " + mPosY + ")"); + + float sizeX = mDrawable.getIntrinsicWidth()/2; + float sizeY = mDrawable.getIntrinsicHeight()/2; + float centerX = detector.getCenterX(); + float centerY = detector.getCenterY(); + float diffX = centerX - mPosX; + float diffY = centerY - mPosY; + diffX = diffX*scale - diffX; + diffY = diffY*scale - diffY; + mPosX -= diffX; + mPosY -= diffY; + mMatrix.reset(); + mMatrix.postTranslate(-sizeX, -sizeY); + mMatrix.postScale(mScale, mScale); + mMatrix.postTranslate(mPosX, mPosY); + + invalidate(); + + return true; + } + + public boolean onTransformBegin(TransformGestureDetector detector) { + return true; + } + + public boolean onTransformEnd(TransformGestureDetector detector) { + return true; + } + + public boolean onTransformFling(TransformGestureDetector detector) { + return false; + } + + } + + public TransformView(Context context) { + super(context); + mMatrix = new Matrix(); + mDetector = new TransformGestureDetector(context, new Listener()); + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + mPosX = metrics.widthPixels/2; + mPosY = metrics.heightPixels/2; + } + + public void setDrawable(Drawable d) { + mDrawable = d; + + float sizeX = mDrawable.getIntrinsicWidth()/2; + float sizeY = mDrawable.getIntrinsicHeight()/2; + mMatrix.reset(); + mMatrix.postTranslate(-sizeX, -sizeY); + mMatrix.postScale(mScale, mScale); + mMatrix.postTranslate(mPosX, mPosY); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean handled = mDetector.onTouchEvent(event); + + int pointerCount = event.getPointerCount(); + Log.d("ttest", "pointerCount: " + pointerCount); + + return handled; + } + + @Override + public void onDraw(Canvas canvas) { + int saveCount = canvas.getSaveCount(); + canvas.save(); + canvas.concat(mMatrix); + mDrawable.draw(canvas); + canvas.restoreToCount(saveCount); + } + } +} diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index de6ff14af41a..ae8f2423e91f 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -1768,31 +1768,33 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass fprintf(stderr, "ERROR: %s\n", error.string()); return -1; } - // asdf --> package.asdf - // .asdf .a.b --> package.asdf package.a.b - // asdf.adsf --> asdf.asdf - String8 rule("-keep class "); - const char* p = name.string(); - const char* q = strchr(p, '.'); - if (p == q) { - rule += pkg; - rule += name; - } else if (q == NULL) { - rule += pkg; - rule += "."; - rule += name; - } else { - rule += name; - } + if (name.length() > 0) { + // asdf --> package.asdf + // .asdf .a.b --> package.asdf package.a.b + // asdf.adsf --> asdf.asdf + String8 rule("-keep class "); + const char* p = name.string(); + const char* q = strchr(p, '.'); + if (p == q) { + rule += pkg; + rule += name; + } else if (q == NULL) { + rule += pkg; + rule += "."; + rule += name; + } else { + rule += name; + } - String8 location = tag; - location += " "; - location += assFile->getSourceFile(); - char lineno[20]; - sprintf(lineno, ":%d", tree.getLineNumber()); - location += lineno; + String8 location = tag; + location += " "; + location += assFile->getSourceFile(); + char lineno[20]; + sprintf(lineno, ":%d", tree.getLineNumber()); + location += lineno; - keep->add(rule, location); + keep->add(rule, location); + } } } } |