diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/bootanimation/Android.mk | 23 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 374 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 14 | ||||
-rw-r--r-- | cmds/bootanimation/bootanimation_main.cpp | 3 | ||||
-rw-r--r-- | cmds/content/src/com/android/commands/content/Content.java | 24 | ||||
-rw-r--r-- | cmds/idmap/create.cpp | 44 | ||||
-rw-r--r-- | cmds/idmap/idmap.cpp | 72 | ||||
-rw-r--r-- | cmds/idmap/idmap.h | 5 | ||||
-rw-r--r-- | cmds/idmap/inspect.cpp | 15 | ||||
-rw-r--r-- | cmds/idmap/scan.cpp | 102 | ||||
-rw-r--r-- | cmds/input/src/com/android/commands/input/Input.java | 1 | ||||
-rw-r--r-- | cmds/media/src/com/android/commands/media/Media.java | 20 | ||||
-rwxr-xr-x | cmds/pm/pm | 1 | ||||
-rw-r--r-- | cmds/screencap/screencap.cpp | 22 | ||||
-rw-r--r-- | cmds/settings/Android.mk | 1 | ||||
-rw-r--r-- | cmds/settings/src/com/android/commands/settings/SettingsCmd.java | 94 | ||||
-rw-r--r-- | cmds/tm/Android.mk | 16 | ||||
-rw-r--r-- | cmds/tm/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | cmds/tm/NOTICE | 190 | ||||
-rw-r--r-- | cmds/tm/src/com/android/commands/tm/Tm.java | 204 | ||||
-rwxr-xr-x | cmds/tm/tm | 6 |
21 files changed, 1093 insertions, 138 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 2ee586f..0c05ded 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -23,7 +23,28 @@ LOCAL_SHARED_LIBRARIES := \ libEGL \ libGLESv1_CM \ libgui \ - libtinyalsa + libtinyalsa \ + libmedia + +ifeq ($(TARGET_CONTINUOUS_SPLASH_ENABLED),true) + LOCAL_CFLAGS += -DCONTINUOUS_SPLASH +endif + +ifeq ($(TARGET_BOOTANIMATION_PRELOAD),true) + LOCAL_CFLAGS += -DPRELOAD_BOOTANIMATION +endif + +ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),true) + LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=0 +endif + +ifeq ($(TARGET_BOOTANIMATION_TEXTURE_CACHE),false) + LOCAL_CFLAGS += -DNO_TEXTURE_CACHE=1 +endif + +ifeq ($(TARGET_BOOTANIMATION_USE_RGB565),true) + LOCAL_CFLAGS += -DUSE_565 +endif LOCAL_MODULE:= bootanimation diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 8f361ce..5afe1e8 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007 The Android Open Source Project + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,9 @@ #include <utils/misc.h> #include <signal.h> #include <time.h> +#include <pthread.h> +#include <sys/select.h> +#include <sys/syscall.h> #include <cutils/properties.h> @@ -54,12 +58,29 @@ #include <GLES/glext.h> #include <EGL/eglext.h> +#include <media/AudioSystem.h> +#include <media/mediaplayer.h> +#include <media/IMediaHTTPService.h> + #include "BootAnimation.h" #include "AudioPlayer.h" #define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip" #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip" #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip" +#define THEME_BOOTANIMATION_FILE "/data/system/theme/bootanimation.zip" + +#define OEM_SHUTDOWN_ANIMATION_FILE "/oem/media/shutdownanimation.zip" +#define SYSTEM_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation.zip" +#define SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE "/system/media/shutdownanimation-encrypted.zip" +#define THEME_SHUTDOWN_ANIMATION_FILE "/data/system/theme/shutdownanimation.zip" + +#define OEM_BOOT_MUSIC_FILE "/oem/media/boot.wav" +#define SYSTEM_BOOT_MUSIC_FILE "/system/media/boot.wav" + +#define OEM_SHUTDOWN_MUSIC_FILE "/oem/media/shutdown.wav" +#define SYSTEM_SHUTDOWN_MUSIC_FILE "/system/media/shutdown.wav" + #define EXIT_PROP_NAME "service.bootanim.exit" namespace android { @@ -68,6 +89,87 @@ static const int ANIM_ENTRY_NAME_MAX = 256; // --------------------------------------------------------------------------- +static pthread_mutex_t mp_lock; +static pthread_cond_t mp_cond; +static bool isMPlayerPrepared = false; +static bool isMPlayerCompleted = false; + +class MPlayerListener : public MediaPlayerListener +{ + void notify(int msg, int /*ext1*/, int /*ext2*/, const Parcel * /*obj*/) + { + switch (msg) { + case MEDIA_NOP: // interface test message + break; + case MEDIA_PREPARED: + pthread_mutex_lock(&mp_lock); + isMPlayerPrepared = true; + pthread_cond_signal(&mp_cond); + pthread_mutex_unlock(&mp_lock); + break; + case MEDIA_PLAYBACK_COMPLETE: + pthread_mutex_lock(&mp_lock); + isMPlayerCompleted = true; + pthread_cond_signal(&mp_cond); + pthread_mutex_unlock(&mp_lock); + break; + default: + break; + } + } +}; + +static unsigned long getFreeMemory(void) +{ + int fd = open("/proc/meminfo", O_RDONLY); + const char* const sums[] = { "MemFree:", "Cached:", NULL }; + const size_t sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 }; + unsigned int num = 2; + + if (fd < 0) { + ALOGW("Unable to open /proc/meminfo"); + return -1; + } + + char buffer[256]; + const int len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) { + ALOGW("Unable to read /proc/meminfo"); + return -1; + } + buffer[len] = 0; + + size_t numFound = 0; + unsigned long mem = 0; + + char* p = buffer; + while (*p && numFound < num) { + int i = 0; + while (sums[i]) { + if (strncmp(p, sums[i], sumsLen[i]) == 0) { + p += sumsLen[i]; + while (*p == ' ') p++; + char* num = p; + while (*p >= '0' && *p <= '9') p++; + if (*p != 0) { + *p = 0; + p++; + if (*p == 0) p--; + } + mem += atoll(num); + numFound++; + break; + } + i++; + } + p++; + } + + return numFound > 0 ? mem : -1; +} + BootAnimation::BootAnimation() : Thread(false), mZip(NULL) { mSession = new SurfaceComposerClient(); @@ -171,16 +273,15 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) if (codec != NULL) { codec->setDitherImage(false); codec->decode(&stream, &bitmap, + #ifdef USE_565 + kRGB_565_SkColorType, + #else kN32_SkColorType, + #endif SkImageDecoder::kDecodePixels_Mode); delete codec; } - // FileMap memory is never released until application exit. - // Release it now as the texture is already loaded and the memory used for - // the packed resource can be released. - delete frame.map; - // ensure we can call getPixels(). No need to call unlock, since the // bitmap will go out of scope when we return from this method. bitmap.lockPixels(); @@ -237,6 +338,18 @@ status_t BootAnimation::readyToRun() { status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo); if (status) return -1; + char value[PROPERTY_VALUE_MAX]; + property_get("persist.panel.orientation", value, "0"); + int orient = atoi(value) / 90; + + if(orient == eOrientation90 || orient == eOrientation270) { + int temp = dinfo.h; + dinfo.h = dinfo.w; + dinfo.w = temp; + } + + Rect destRect(dinfo.w, dinfo.h); + mSession->setDisplayProjection(dtoken, orient, destRect, destRect); // create the native surface sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), @@ -287,21 +400,53 @@ status_t BootAnimation::readyToRun() { char decrypt[PROPERTY_VALUE_MAX]; property_get("vold.decrypt", decrypt, ""); + // Use customized resources for boot and showdown animation + // instead of system predefined boot animation files. bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt); ZipFileRO* zipFile = NULL; if ((encryptedAnimation && - (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) || + (access(getAnimationFileName(IMG_ENC), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_ENC))) != NULL)) || + + ((access(getAnimationFileName(IMG_THM), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_THM))) != NULL)) || - ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) || - ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && - ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) { + ((access(getAnimationFileName(IMG_DATA), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_DATA))) != NULL)) || + + ((access(getAnimationFileName(IMG_SYS), R_OK) == 0) && + ((zipFile = ZipFileRO::open(getAnimationFileName(IMG_SYS))) != NULL))) { mZip = zipFile; } +#ifdef PRELOAD_BOOTANIMATION + // Preload the bootanimation zip on memory, so we don't stutter + // when showing the animation + FILE* fd; + if (encryptedAnimation && access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, "r"); + else if (access(OEM_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(OEM_BOOTANIMATION_FILE, "r"); + else if (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) + fd = fopen(SYSTEM_BOOTANIMATION_FILE, "r"); + else + return NO_ERROR; + + if (fd != NULL) { + // Since including fcntl.h doesn't give us the wrapper, use the syscall. + // 32 bits takes LO/HI offset (we don't care about endianness of 0). +#if defined(__aarch64__) || defined(__x86_64__) + if (syscall(__NR_readahead, fd, 0, INT_MAX)) +#else + if (syscall(__NR_readahead, fd, 0, 0, INT_MAX)) +#endif + ALOGW("Unable to cache the animation"); + fclose(fd); + } +#endif + return NO_ERROR; } @@ -452,6 +597,7 @@ bool BootAnimation::readFile(const char* name, String8& outString) bool BootAnimation::movie() { + char value[PROPERTY_VALUE_MAX]; String8 desString; if (!readFile("desc.txt", desString)) { @@ -556,11 +702,14 @@ bool BootAnimation::movie() mZip->endIteration(cookie); +#ifndef CONTINUOUS_SPLASH glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glDisable(GL_BLEND); +#endif + glBindTexture(GL_TEXTURE_2D, 0); glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); @@ -576,11 +725,45 @@ bool BootAnimation::movie() Region clearReg(Rect(mWidth, mHeight)); clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); + pthread_mutex_init(&mp_lock, NULL); + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&mp_cond, &attr); + for (size_t i=0 ; i<pcount ; i++) { const Animation::Part& part(animation.parts[i]); const size_t fcount = part.frames.size(); + + // can be 1, 0, or not set + #ifdef NO_TEXTURE_CACHE + const int noTextureCache = NO_TEXTURE_CACHE; + #else + const int noTextureCache = + ((animation.width * animation.height * fcount) > 48 * 1024 * 1024) ? 1 : 0; + #endif + glBindTexture(GL_TEXTURE_2D, 0); + /*calculate if we need to runtime save memory + * condition: runtime free memory is less than the textures that will used. + * needSaveMem default to be false + */ + GLint mMaxTextureSize; + bool needSaveMem = false; + GLuint mTextureid; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); + //ALOGD("freemem:%ld, %d", getFreeMemory(), mMaxTextureSize); + if(getFreeMemory() < mMaxTextureSize * mMaxTextureSize * fcount / 1024 || noTextureCache) { + ALOGD("Use save memory method, maybe small fps in actual."); + needSaveMem = true; + glGenTextures(1, &mTextureid); + glBindTexture(GL_TEXTURE_2D, mTextureid); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + } + for (int r=0 ; !part.count || r<part.count ; r++) { // Exit any non playuntil complete parts immediately if(exitPending() && !part.playUntilComplete) @@ -601,10 +784,10 @@ bool BootAnimation::movie() const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); - if (r > 0) { + if (r > 0 && !needSaveMem) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { - if (part.count != 1) { + if (!needSaveMem && part.count != 1) { glGenTextures(1, &frame.tid); glBindTexture(GL_TEXTURE_2D, frame.tid); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -657,18 +840,177 @@ bool BootAnimation::movie() } // free the textures for this part - if (part.count != 1) { + if (!needSaveMem && part.count != 1) { for (size_t j=0 ; j<fcount ; j++) { const Animation::Frame& frame(part.frames[j]); glDeleteTextures(1, &frame.tid); } } + + if (needSaveMem) { + glDeleteTextures(1, &mTextureid); + } + + } + + property_get("persist.sys.silent", value, "null"); + if (strncmp(value, "1", 1) != 0) { + ALOGD("playing boot audio here"); + playBackgroundMusic(); + } + + if (isMPlayerPrepared) { + ALOGD("waiting for media player to complete."); + struct timespec timeout; + clock_gettime(CLOCK_MONOTONIC, &timeout); + timeout.tv_sec += 5; //timeout after 5s. + + pthread_mutex_lock(&mp_lock); + while (!isMPlayerCompleted) { + int err = pthread_cond_timedwait(&mp_cond, &mp_lock, &timeout); + if (err == ETIMEDOUT) { + break; + } + } + pthread_mutex_unlock(&mp_lock); + ALOGD("media player is completed."); } + pthread_cond_destroy(&mp_cond); + pthread_mutex_destroy(&mp_lock); + return false; } -// --------------------------------------------------------------------------- +const char *BootAnimation::getAnimationFileName(ImageID image) +{ + const char *fileName[2][4] = { { OEM_BOOTANIMATION_FILE, + SYSTEM_BOOTANIMATION_FILE, + SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, + THEME_BOOTANIMATION_FILE }, { + OEM_SHUTDOWN_ANIMATION_FILE, + SYSTEM_SHUTDOWN_ANIMATION_FILE, + SYSTEM_ENCRYPTED_SHUTDOWN_ANIMATION_FILE, + THEME_SHUTDOWN_ANIMATION_FILE} }; + int state; + char sku[PROPERTY_VALUE_MAX]; + char skusuffix[PATH_MAX]; + + state = checkBootState() ? 0 : 1; + + property_get("ro.prebundled.mcc", sku, "000"); + sprintf(skusuffix,"-%s",sku); + + String16 skuPath(fileName[state][image]); + skuPath.insert(skuPath.size()-4,String16(skusuffix)); + + if (access(String8(skuPath).string(), R_OK) == 0) + return (char *)String8(skuPath).string(); + + return fileName[state][image]; +} + +const char *BootAnimation::getBootRingtoneFileName(ImageID image) +{ + if (image == IMG_ENC) { + return NULL; + } + + const char *fileName[2][2] = { { OEM_BOOT_MUSIC_FILE, + SYSTEM_BOOT_MUSIC_FILE }, { + OEM_SHUTDOWN_MUSIC_FILE, + SYSTEM_SHUTDOWN_MUSIC_FILE } }; + int state; + + state = checkBootState() ? 0 : 1; + + return fileName[state][image]; +} + +static void* playMusic(void* arg) +{ + int index = 0; + char *fileName = (char *)arg; + sp<MediaPlayer> mp = new MediaPlayer(); + sp<MPlayerListener> mListener = new MPlayerListener(); + if (mp != NULL) { + ALOGD("starting to play %s", fileName); + mp->setListener(mListener); + + if (mp->setDataSource(NULL, fileName, NULL) == NO_ERROR) { + mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE); + mp->prepare(); + } else { + ALOGE("failed to setDataSource for %s", fileName); + return NULL; + } + //waiting for media player is prepared. + pthread_mutex_lock(&mp_lock); + while (!isMPlayerPrepared) { + pthread_cond_wait(&mp_cond, &mp_lock); + } + pthread_mutex_unlock(&mp_lock); + + audio_devices_t device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE); + AudioSystem::initStreamVolume(AUDIO_STREAM_ENFORCED_AUDIBLE,0,7); + AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, 7, device); + + AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device); + if (index != 0) { + ALOGD("playing %s", fileName); + mp->seekTo(0); + mp->start(); + } else { + ALOGW("current volume is zero."); + } + } + return NULL; +} + +void BootAnimation::playBackgroundMusic(void) +{ + //Shutdown music is playing in ShutdownThread.java + if (!checkBootState()) { + return; + } + + /* Make sure sound cards are populated */ + FILE* fp = NULL; + if ((fp = fopen("/proc/asound/cards", "r")) == NULL) { + ALOGW("Cannot open /proc/asound/cards file to get sound card info."); + } + + char value[PROPERTY_VALUE_MAX]; + property_get("qcom.audio.init", value, "null"); + if (strncmp(value, "complete", 8) != 0) { + ALOGW("Audio service is not initiated."); + } + + fclose(fp); + + const char *fileName; + if (((fileName = getBootRingtoneFileName(IMG_DATA)) != NULL && access(fileName, R_OK) == 0) || + ((fileName = getBootRingtoneFileName(IMG_SYS)) != NULL + && access(fileName, R_OK) == 0)) { + pthread_t tid; + pthread_create(&tid, NULL, playMusic, (void *)fileName); + pthread_join(tid, NULL); + } +} +bool BootAnimation::checkBootState(void) +{ + char value[PROPERTY_VALUE_MAX]; + bool ret = true; + + property_get("sys.shutdown.requested", value, "null"); + if (strncmp(value, "null", 4) != 0) { + ret = false; + } + + return ret; } -; // namespace android + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index f968b25..a0f84da 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -40,6 +40,12 @@ class SurfaceControl; class BootAnimation : public Thread, public IBinder::DeathRecipient { public: + enum { + eOrientationDefault = 0, + eOrientation90 = 1, + eOrientation180 = 2, + eOrientation270 = 3, + }; BootAnimation(); virtual ~BootAnimation(); @@ -87,12 +93,18 @@ private: bool readFile(const char* name, String8& outString); bool movie(); + enum ImageID { IMG_DATA = 0, IMG_SYS = 1, IMG_ENC = 2, IMG_THM = 3 }; + const char *getAnimationFileName(ImageID image); + const char *getBootRingtoneFileName(ImageID image); + void playBackgroundMusic(); + bool checkBootState(); void checkExit(); + void checkShowAndroid(); sp<SurfaceComposerClient> mSession; sp<AudioPlayer> mAudioPlayer; AssetManager mAssets; - Texture mAndroid[2]; + Texture mAndroid[3]; int mWidth; int mHeight; EGLDisplay mDisplay; diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index 48a34e7..50e4b1f 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -38,8 +38,9 @@ int main() property_get("debug.sf.nobootanimation", value, "0"); int noBootAnimation = atoi(value); ALOGI_IF(noBootAnimation, "boot animation disabled"); - if (!noBootAnimation) { + property_get("ro.alarm_boot", value, "false"); + if (!noBootAnimation && strcmp(value, "true")) { sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool(); diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index c0ed893..1d8b8b1 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -103,10 +103,12 @@ public class Content { + "--where \"name=\'new_setting\'\"\n" + "\n" + "usage: adb shell content query --uri <URI> [--user <USER_ID>]" - + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n" + + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>] " + + " [--show-type <SHOW-TYPE>] \n" + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" + " <SORT_ORDER> is the order in which rows in the result should be sorted.\n" + + " <SHOW-TYPE> if true shows the type of value of each projection column" + " Example:\n" + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + "equal to \"new_setting\" and sort the result by name in ascending order.\n" @@ -142,6 +144,7 @@ public class Content { private static final String ARGUMENT_METHOD = "--method"; private static final String ARGUMENT_ARG = "--arg"; private static final String ARGUMENT_EXTRA = "--extra"; + private static final String ARGUMENT_SHOW_TYPE = "--show-type"; private static final String TYPE_BOOLEAN = "b"; private static final String TYPE_STRING = "s"; private static final String TYPE_INTEGER = "i"; @@ -316,6 +319,7 @@ public class Content { String[] projection = null; String sort = null; String where = null; + boolean showType = false; for (String argument; (argument = mTokenizer.nextArg())!= null;) { if (ARGUMENT_URI.equals(argument)) { uri = Uri.parse(argumentValueRequired(argument)); @@ -327,6 +331,8 @@ public class Content { sort = argumentValueRequired(argument); } else if (ARGUMENT_PROJECTION.equals(argument)) { projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*"); + } else if (ARGUMENT_SHOW_TYPE.equals(argument)) { + showType = argumentValueRequiredForBoolean(argument); } else { throw new IllegalArgumentException("Unsupported argument: " + argument); } @@ -335,7 +341,7 @@ public class Content { throw new IllegalArgumentException("Content provider URI not specified." + " Did you specify --uri argument?"); } - return new QueryCommand(uri, userId, projection, where, sort); + return new QueryCommand(uri, userId, projection, where, sort, showType); } private void parseBindValue(ContentValues values) { @@ -367,6 +373,14 @@ public class Content { } } + private boolean argumentValueRequiredForBoolean(String argument) { + String value = mTokenizer.nextArg(); + if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { + throw new IllegalArgumentException("No value for argument: " + argument); + } + return value.equals("true"); + } + private String argumentValueRequired(String argument) { String value = mTokenizer.nextArg(); if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { @@ -539,12 +553,15 @@ public class Content { private static class QueryCommand extends DeleteCommand { final String[] mProjection; final String mSortOrder; + final boolean mShowType; public QueryCommand( - Uri uri, int userId, String[] projection, String where, String sortOrder) { + Uri uri, int userId, String[] projection, String where, String sortOrder, + boolean showType) { super(uri, userId, where); mProjection = projection; mSortOrder = sortOrder; + mShowType = showType; } @Override @@ -590,6 +607,7 @@ public class Content { break; } builder.append(columnName).append("=").append(columnValue); + if (mShowType) builder.append(", type=").append(type); } System.out.println(builder); } while (cursor.moveToNext()); diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp index 41395f1..dd0554e 100644 --- a/cmds/idmap/create.cpp +++ b/cmds/idmap/create.cpp @@ -33,6 +33,7 @@ namespace { int open_idmap(const char *path) { int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)); + bool needUnlink = true; if (fd == -1) { ALOGD("error: open %s: %s\n", path, strerror(errno)); goto fail; @@ -41,8 +42,10 @@ namespace { ALOGD("error: fchmod %s: %s\n", path, strerror(errno)); goto fail; } - if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) { + if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX)) != 0) { ALOGD("error: flock %s: %s\n", path, strerror(errno)); + // If the file is locked by another process, then we needn't unlink the file. + needUnlink = false; goto fail; } @@ -50,7 +53,7 @@ namespace { fail: if (fd != -1) { close(fd); - unlink(path); + if (needUnlink) unlink(path); } return -1; } @@ -150,26 +153,26 @@ fail: } int create_idmap(const char *target_apk_path, const char *overlay_apk_path, - uint32_t **data, size_t *size) + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, uint32_t **data, + size_t *size) { uint32_t target_crc, overlay_crc; - if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME, - &target_crc) == -1) { - return -1; - } - if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME, - &overlay_crc) == -1) { - return -1; - } + + // In the original implementation, crc of the res tables are generated + // theme apks however do not need a restable, everything is in assets/ + // instead timestamps are used + target_crc = 0; + overlay_crc = 0; AssetManager am; - bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc, - data, size); + bool b = am.createIdmap(target_apk_path, overlay_apk_path, cache_path, target_crc, + overlay_crc, target_hash, overlay_hash, data, size); return b ? 0 : -1; } int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path, - int fd, bool check_if_stale) + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, int fd, + bool check_if_stale) { if (check_if_stale) { if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) { @@ -181,7 +184,8 @@ fail: uint32_t *data = NULL; size_t size; - if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) { + if (create_idmap(target_apk_path, overlay_apk_path, cache_path, target_hash, overlay_hash, + &data, &size) == -1) { return -1; } @@ -196,6 +200,7 @@ fail: } int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, const char *idmap_path) { if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) { @@ -208,7 +213,8 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, return EXIT_FAILURE; } - int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false); + int r = create_and_write_idmap(target_apk_path, overlay_apk_path, cache_path, + target_hash, overlay_hash, fd, false); close(fd); if (r != 0) { unlink(idmap_path); @@ -216,8 +222,10 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd) +int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, int fd) { - return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ? + return create_and_write_idmap(target_apk_path, overlay_apk_path, cache_path, target_hash, + overlay_hash, fd, true) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp index 90cfa2c..cc3f231 100644 --- a/cmds/idmap/idmap.cpp +++ b/cmds/idmap/idmap.cpp @@ -66,29 +66,31 @@ EXAMPLES \n\ Display an idmap file: \n\ \n\ $ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\ - SECTION ENTRY VALUE COMMENT \n\ - IDMAP HEADER magic 0x706d6469 \n\ - base crc 0xb65a383f \n\ - overlay crc 0x7b9675e8 \n\ - base path .......... /path/to/target.apk \n\ - overlay path .......... /path/to/overlay.apk \n\ - DATA HEADER target pkg 0x0000007f \n\ - types count 0x00000003 \n\ - DATA BLOCK target type 0x00000002 \n\ - overlay type 0x00000002 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 drawable/drawable \n\ - DATA BLOCK target type 0x00000003 \n\ - overlay type 0x00000003 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 xml/integer \n\ - DATA BLOCK target type 0x00000004 \n\ - overlay type 0x00000004 \n\ - entry count 0x00000001 \n\ - entry offset 0x00000000 \n\ - entry 0x00000000 raw/lorem_ipsum \n\ + SECTION ENTRY VALUE COMMENT \n\ + IDMAP HEADER magic 0x706d6469 \n\ + base crc 0xb65a383f \n\ + overlay crc 0x7b9675e8 \n\ + base mtime 0x1eb47d51 \n\ + overlay mtime 0x185f87a2 \n\ + base path .......... /path/to/target.apk \n\ + overlay path .......... /path/to/overlay.apk \n\ + DATA HEADER target pkg 0x0000007f \n\ + types count 0x00000003 \n\ + DATA BLOCK target type 0x00000002 \n\ + overlay type 0x00000002 \n\ + entry count 0x00000001 \n\ + entry offset 0x00000000 \n\ + entry 0x00000000 drawable/drawable \n\ + DATA BLOCK target type 0x00000003 \n\ + overlay type 0x00000003 \n\ + entry count 0x00000001 \n\ + entry offset 0x00000000 \n\ + entry 0x00000000 xml/integer \n\ + DATA BLOCK target type 0x00000004 \n\ + overlay type 0x00000004 \n\ + entry count 0x00000001 \n\ + entry offset 0x00000000 \n\ + entry 0x00000000 raw/lorem_ipsum \n\ \n\ In this example, the overlay package provides three alternative resource values:\n\ drawable/drawable, xml/integer, and raw/lorem_ipsum \n\ @@ -120,7 +122,8 @@ NOTES \n\ } int maybe_create_fd(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_str) + const char *cache_path, const char *idmap_str, const char *target_hash_str, + const char *overlay_hash_str) { // anyone (not just root or system) may do --fd -- the file has // already been opened by someone else on our behalf @@ -141,12 +144,16 @@ NOTES \n\ ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno)); return -1; } + int target_hash = strtol(target_hash_str, 0, 10); + int overlay_hash = strtol(overlay_hash_str, 0, 10); - return idmap_create_fd(target_apk_path, overlay_apk_path, idmap_fd); + return idmap_create_fd(target_apk_path, overlay_apk_path, cache_path, target_hash, + overlay_hash, idmap_fd); } int maybe_create_path(const char *target_apk_path, const char *overlay_apk_path, - const char *idmap_path) + const char *cache_path, const char *idmap_path, const char *target_hash_str, + const char *overlay_hash_str) { if (!verify_root_or_system()) { fprintf(stderr, "error: permission denied: not user root or user system\n"); @@ -163,7 +170,10 @@ NOTES \n\ return -1; } - return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path); + int target_hash = strtol(target_hash_str, 0, 10); + int overlay_hash = strtol(overlay_hash_str, 0, 10); + return idmap_create_path(target_apk_path, overlay_apk_path, cache_path, target_hash, + overlay_hash, idmap_path); } int maybe_scan(const char *overlay_dir, const char *target_package_name, @@ -222,12 +232,12 @@ int main(int argc, char **argv) return 0; } - if (argc == 5 && !strcmp(argv[1], "--fd")) { - return maybe_create_fd(argv[2], argv[3], argv[4]); + if (argc == 8 && !strcmp(argv[1], "--fd")) { + return maybe_create_fd(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); } - if (argc == 5 && !strcmp(argv[1], "--path")) { - return maybe_create_path(argv[2], argv[3], argv[4]); + if (argc == 8 && !strcmp(argv[1], "--path")) { + return maybe_create_path(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); } if (argc == 6 && !strcmp(argv[1], "--scan")) { diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h index f507dd8..6a9c5ef 100644 --- a/cmds/idmap/idmap.h +++ b/cmds/idmap/idmap.h @@ -19,9 +19,12 @@ #endif int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, const char *idmap_path); -int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd); +int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, + const char *cache_path, uint32_t target_hash, uint32_t overlay_hash, + int fd); // Regarding target_package_name: the idmap_scan implementation should // be able to extract this from the manifest in target_apk_path, diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp index f6afc85..3087e6e 100644 --- a/cmds/idmap/inspect.cpp +++ b/cmds/idmap/inspect.cpp @@ -200,6 +200,18 @@ namespace { } print("", "overlay crc", i, ""); + err = buf.nextUint32(&i); + if (err != NO_ERROR) { + return err; + } + print("", "base mtime", i, ""); + + err = buf.nextUint32(&i); + if (err != NO_ERROR) { + return err; + } + print("", "overlay mtime", i, ""); + err = buf.nextPath(path); if (err != NO_ERROR) { // printe done from IdmapBuffer::nextPath @@ -223,7 +235,8 @@ namespace { } status_t parse_data(IdmapBuffer& buf, const AssetManager& am) { - const uint32_t packageId = am.getResources().getBasePackageId(0); + const ResTable& rt = am.getResources(); + const uint32_t packageId = rt.getBasePackageId(rt.getBasePackageCount() - 1); uint16_t data16; status_t err = buf.nextUint16(&data16); diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp index 612a7eb..b319e68 100644 --- a/cmds/idmap/scan.cpp +++ b/cmds/idmap/scan.cpp @@ -25,8 +25,7 @@ namespace { bool operator<(Overlay const& rhs) const { - // Note: order is reversed by design - return rhs.priority < priority; + return rhs.priority > priority; } String8 apk_path; @@ -165,6 +164,62 @@ namespace { delete dataMap; return priority; } + + int idmap_scan(const char *overlay_dir, const char *target_package_name, + const char *target_apk_path, const char *idmap_dir, + SortedVector<Overlay>& overlayVector) + { + DIR *dir = opendir(overlay_dir); + if (dir == NULL) { + return EXIT_FAILURE; + } + + struct dirent *dirent; + while ((dirent = readdir(dir)) != NULL) { + struct stat st; + char overlay_apk_path[PATH_MAX + 1]; + snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name); + if (stat(overlay_apk_path, &st) < 0) { + continue; + } + if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { + continue; + } + + if (S_ISDIR(st.st_mode)) { + String8 dir_name = String8(overlay_apk_path).getPathLeaf(); + if (dir_name == "." || dir_name == "..") { + // Skip the "." and ".." dir. + continue; + } + idmap_scan(overlay_apk_path, target_package_name, target_apk_path, idmap_dir, + overlayVector); + } else { + int priority = parse_apk(overlay_apk_path, target_package_name); + if (priority < 0) { + continue; + } + + String8 idmap_path(idmap_dir); + idmap_path.appendPath(flatten_path(overlay_apk_path + 1)); + idmap_path.append("@idmap"); + + if (idmap_create_path(target_apk_path, overlay_apk_path, NULL, 0, 0, + idmap_path.string()) != 0) { + ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n", + target_apk_path, overlay_apk_path, idmap_path.string()); + continue; + } + + Overlay overlay(String8(overlay_apk_path), idmap_path, priority); + overlayVector.add(overlay); + } + } + + closedir(dir); + + return EXIT_SUCCESS; + } } int idmap_scan(const char *overlay_dir, const char *target_package_name, @@ -176,48 +231,13 @@ int idmap_scan(const char *overlay_dir, const char *target_package_name, return EXIT_FAILURE; } - DIR *dir = opendir(overlay_dir); - if (dir == NULL) { - return EXIT_FAILURE; - } - SortedVector<Overlay> overlayVector; - struct dirent *dirent; - while ((dirent = readdir(dir)) != NULL) { - struct stat st; - char overlay_apk_path[PATH_MAX + 1]; - snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name); - if (stat(overlay_apk_path, &st) < 0) { - continue; - } - if (!S_ISREG(st.st_mode)) { - continue; - } - - int priority = parse_apk(overlay_apk_path, target_package_name); - if (priority < 0) { - continue; - } - - String8 idmap_path(idmap_dir); - idmap_path.appendPath(flatten_path(overlay_apk_path + 1)); - idmap_path.append("@idmap"); - - if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) { - ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n", - target_apk_path, overlay_apk_path, idmap_path.string()); - continue; - } - - Overlay overlay(String8(overlay_apk_path), idmap_path, priority); - overlayVector.add(overlay); - } - - closedir(dir); + int res = idmap_scan(overlay_dir, target_package_name, target_apk_path, idmap_dir, + overlayVector); - if (!writePackagesList(filename.string(), overlayVector)) { + if (res == EXIT_FAILURE || !writePackagesList(filename.string(), overlayVector)) { return EXIT_FAILURE; } - return EXIT_SUCCESS; + return res; } diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index 2a7c79b..40148c6 100644 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -47,6 +47,7 @@ public class Input { put("touchpad", InputDevice.SOURCE_TOUCHPAD); put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION); put("joystick", InputDevice.SOURCE_JOYSTICK); + put("gesture", InputDevice.SOURCE_GESTURE_SENSOR); }}; diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index d7f23cb..d185b56 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -222,6 +222,26 @@ public class Media extends BaseCommand { System.out.println("onVolumeInfoChanged " + info); } + @Override + public void onPlayItemResponse(boolean success) throws RemoteException { + System.out.println("onPlayItemResponse "); + } + + @Override + public void onUpdateNowPlayingEntries(long[] playList) throws RemoteException { + System.out.println("onUpdateNowPlayingEntries "); + } + + @Override + public void onUpdateFolderInfoBrowsedPlayer(String stringUri) throws RemoteException { + System.out.println("onUpdateFolderInfoBrowsedPlayer "); + } + + @Override + public void onUpdateNowPlayingContentChange() throws RemoteException { + System.out.println("onUpdateNowPlayingContentChange "); + } + void printUsageMessage() { try { System.out.println("V2Monitoring session " + mController.getTag() @@ -1,3 +1,4 @@ +#!/system/bin/sh # Script to start "pm" on the device, which has a very rudimentary # shell. # diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index c469ae4..865a216 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -50,6 +50,7 @@ static void usage(const char* pname) "usage: %s [-hp] [-d display-id] [FILENAME]\n" " -h: this message\n" " -p: save the file as a png.\n" + " -j: save the file as a jpeg.\n" " -d: specify the display id to capture, default %d.\n" "If FILENAME ends with .png it will be saved as a png.\n" "If FILENAME is not given, the results will be printed to stdout.\n", @@ -112,13 +113,17 @@ int main(int argc, char** argv) const char* pname = argv[0]; bool png = false; + bool jpeg = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; - while ((c = getopt(argc, argv, "phd:")) != -1) { + while ((c = getopt(argc, argv, "pjhd:")) != -1) { switch (c) { case 'p': png = true; break; + case 'j': + jpeg = true; + break; case 'd': displayId = atoi(optarg); break; @@ -143,8 +148,14 @@ int main(int argc, char** argv) return 1; } const int len = strlen(fn); - if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { - png = true; + if (len >= 4) { + if (0 == strcmp(fn+len-4, ".png")) { + png = true; + } else if (0 == strcmp(fn+len-4, ".jpg")) { + jpeg = true; + } else if (len > 4 && 0 == strcmp(fn+len-5, ".jpeg")) { + jpeg = true; + } } } @@ -220,11 +231,12 @@ int main(int argc, char** argv) } if (base != NULL) { - if (png) { + if (png || jpeg) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), - SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); + (png ? SkImageEncoder::kPNG_Type : SkImageEncoder::kJPEG_Type), + SkImageEncoder::kDefaultQuality)); if (data.get()) { write(fd, data->data(), data->size()); } diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk index 05deb99..c397535 100644 --- a/cmds/settings/Android.mk +++ b/cmds/settings/Android.mk @@ -4,6 +4,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.internal LOCAL_MODULE := settings LOCAL_MODULE_TAGS := optional include $(BUILD_JAVA_LIBRARY) diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java index c27d0c0..64610fe 100644 --- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java +++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java @@ -29,6 +29,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; +import android.text.TextUtils; +import cyanogenmod.providers.CMSettings; import java.util.ArrayList; import java.util.Collections; @@ -36,6 +38,9 @@ import java.util.List; public final class SettingsCmd { + private static final String SETTINGS_AUTHORITY = Settings.AUTHORITY; + private static final String CMSETTINGS_AUTHORITY = CMSettings.AUTHORITY; + enum CommandVerb { UNSPECIFIED, GET, @@ -51,6 +56,7 @@ public final class SettingsCmd { String mTable = null; String mKey = null; String mValue = null; + boolean mUseCMSettingsProvider = false; public static void main(String[] args) { if (args == null || args.length < 2) { @@ -77,6 +83,8 @@ public final class SettingsCmd { break; } mUser = Integer.parseInt(nextArg()); + } else if ("--cm".equals(arg)) { + mUseCMSettingsProvider = true; } else if (mVerb == CommandVerb.UNSPECIFIED) { if ("get".equalsIgnoreCase(arg)) { mVerb = CommandVerb.GET; @@ -133,13 +141,21 @@ public final class SettingsCmd { mUser = UserHandle.USER_OWNER; } + // Implicitly use CMSettings provider if the setting is a legacy setting + if (!mUseCMSettingsProvider && isLegacySetting(mTable, mKey)) { + System.err.println("'" + mKey + "' has moved to CMSettings. Use --cm to avoid " + + "this warning in the future."); + mUseCMSettingsProvider = true; + } + try { IActivityManager activityManager = ActivityManagerNative.getDefault(); IContentProvider provider = null; IBinder token = new Binder(); try { ContentProviderHolder holder = activityManager.getContentProviderExternal( - "settings", UserHandle.USER_OWNER, token); + mUseCMSettingsProvider ? CMSETTINGS_AUTHORITY : SETTINGS_AUTHORITY, + UserHandle.USER_OWNER, token); if (holder == null) { throw new IllegalStateException("Could not find settings provider"); } @@ -182,9 +198,15 @@ public final class SettingsCmd { } private List<String> listForUser(IContentProvider provider, int userHandle, String table) { - final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI - : "secure".equals(table) ? Settings.Secure.CONTENT_URI - : "global".equals(table) ? Settings.Global.CONTENT_URI + final Uri systemUri = mUseCMSettingsProvider ? CMSettings.System.CONTENT_URI + : Settings.System.CONTENT_URI; + final Uri secureUri = mUseCMSettingsProvider ? CMSettings.Secure.CONTENT_URI + : Settings.Secure.CONTENT_URI; + final Uri globalUri = mUseCMSettingsProvider ? CMSettings.Global.CONTENT_URI + : Settings.Global.CONTENT_URI; + final Uri uri = "system".equals(table) ? systemUri + : "secure".equals(table) ? secureUri + : "global".equals(table) ? globalUri : null; final ArrayList<String> lines = new ArrayList<String>(); if (uri == null) { @@ -220,10 +242,16 @@ public final class SettingsCmd { String getForUser(IContentProvider provider, int userHandle, final String table, final String key) { + final String systemGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_SYSTEM + : Settings.CALL_METHOD_GET_SYSTEM; + final String secureGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_SECURE + : Settings.CALL_METHOD_GET_SECURE; + final String globalGetCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_GET_GLOBAL + : Settings.CALL_METHOD_GET_GLOBAL; final String callGetCommand; - if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM; - else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE; - else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL; + if ("system".equals(table)) callGetCommand = systemGetCommand; + else if ("secure".equals(table)) callGetCommand = secureGetCommand; + else if ("global".equals(table)) callGetCommand = globalGetCommand; else { System.err.println("Invalid table; no put performed"); throw new IllegalArgumentException("Invalid table " + table); @@ -232,7 +260,8 @@ public final class SettingsCmd { String result = null; try { Bundle arg = new Bundle(); - arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); + arg.putInt(mUseCMSettingsProvider ? CMSettings.CALL_METHOD_USER_KEY + : Settings.CALL_METHOD_USER_KEY, userHandle); Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg); if (b != null) { result = b.getPairValue(); @@ -245,10 +274,16 @@ public final class SettingsCmd { void putForUser(IContentProvider provider, int userHandle, final String table, final String key, final String value) { + final String systemPutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_SYSTEM + : Settings.CALL_METHOD_PUT_SYSTEM; + final String securePutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_SECURE + : Settings.CALL_METHOD_PUT_SECURE; + final String globalPutCommand = mUseCMSettingsProvider ? CMSettings.CALL_METHOD_PUT_GLOBAL + : Settings.CALL_METHOD_PUT_GLOBAL; final String callPutCommand; - if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM; - else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE; - else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL; + if ("system".equals(table)) callPutCommand = systemPutCommand; + else if ("secure".equals(table)) callPutCommand = securePutCommand; + else if ("global".equals(table)) callPutCommand = globalPutCommand; else { System.err.println("Invalid table; no put performed"); return; @@ -257,7 +292,8 @@ public final class SettingsCmd { try { Bundle arg = new Bundle(); arg.putString(Settings.NameValueTable.VALUE, value); - arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); + arg.putInt(mUseCMSettingsProvider ? CMSettings.CALL_METHOD_USER_KEY + : Settings.CALL_METHOD_USER_KEY, userHandle); provider.call(resolveCallingPackage(), callPutCommand, key, arg); } catch (RemoteException e) { System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle); @@ -266,10 +302,16 @@ public final class SettingsCmd { int deleteForUser(IContentProvider provider, int userHandle, final String table, final String key) { + final Uri systemUri = mUseCMSettingsProvider ? CMSettings.System.getUriFor(key) + : Settings.System.getUriFor(key); + final Uri secureUri = mUseCMSettingsProvider ? CMSettings.Secure.getUriFor(key) + : Settings.Secure.getUriFor(key); + final Uri globalUri = mUseCMSettingsProvider ? CMSettings.Global.getUriFor(key) + : Settings.Global.getUriFor(key); Uri targetUri; - if ("system".equals(table)) targetUri = Settings.System.getUriFor(key); - else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key); - else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key); + if ("system".equals(table)) targetUri = systemUri; + else if ("secure".equals(table)) targetUri = secureUri; + else if ("global".equals(table)) targetUri = globalUri; else { System.err.println("Invalid table; no delete performed"); throw new IllegalArgumentException("Invalid table " + table); @@ -286,12 +328,26 @@ public final class SettingsCmd { } private static void printUsage() { - System.err.println("usage: settings [--user NUM] get namespace key"); - System.err.println(" settings [--user NUM] put namespace key value"); - System.err.println(" settings [--user NUM] delete namespace key"); - System.err.println(" settings [--user NUM] list namespace"); + System.err.println("usage: settings [--user NUM] [--cm] get namespace key"); + System.err.println(" settings [--user NUM] [--cm] put namespace key value"); + System.err.println(" settings [--user NUM] [--cm] delete namespace key"); + System.err.println(" settings [--user NUM] [--cm] list namespace"); System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive"); System.err.println("If '--user NUM' is not given, the operations are performed on the owner user."); + System.err.println("If '--cm' is given, the operations are performed on the CMSettings provider."); + } + + private static boolean isLegacySetting(String table, String key) { + if (!TextUtils.isEmpty(key)) { + if ("system".equals(table)) { + return CMSettings.System.isLegacySetting(key); + } else if ("secure".equals(table)) { + return CMSettings.Secure.isLegacySetting(key); + } else if ("global".equals(table)) { + return CMSettings.Global.isLegacySetting(key); + } + } + return false; } public static String resolveCallingPackage() { diff --git a/cmds/tm/Android.mk b/cmds/tm/Android.mk new file mode 100644 index 0000000..97e8ee4 --- /dev/null +++ b/cmds/tm/Android.mk @@ -0,0 +1,16 @@ +# Copyright 2015 The CyanogenMod Project +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.internal +LOCAL_MODULE := tm +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := tm +LOCAL_SRC_FILES := tm +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/tm/MODULE_LICENSE_APACHE2 b/cmds/tm/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/tm/MODULE_LICENSE_APACHE2 diff --git a/cmds/tm/NOTICE b/cmds/tm/NOTICE new file mode 100644 index 0000000..0820f6d --- /dev/null +++ b/cmds/tm/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2015, The CyanogenMod Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/cmds/tm/src/com/android/commands/tm/Tm.java b/cmds/tm/src/com/android/commands/tm/Tm.java new file mode 100644 index 0000000..0ba5cb9 --- /dev/null +++ b/cmds/tm/src/com/android/commands/tm/Tm.java @@ -0,0 +1,204 @@ +/* +** +** Copyright 2015, The CyanogenMod 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.commands.tm; + +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.AndroidException; +import com.android.internal.os.BaseCommand; + +import cyanogenmod.app.CMContextConstants; +import cyanogenmod.themes.IThemeService; +import cyanogenmod.themes.ThemeChangeRequest; + +import org.cyanogenmod.internal.util.ThemeUtils; + +import java.io.PrintStream; +import java.util.List; +import java.util.Map; + +public class Tm extends BaseCommand { + private static final String SYSTEM_THEME = "system"; + + IThemeService mTs; + IPackageManager mPm; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Tm()).run(args); + } + + public void onShowUsage(PrintStream out) { + List<String> components = ThemeUtils.getAllComponents(); + StringBuilder sb = new StringBuilder(); + sb.append("usage: tm [subcommand] [options]\n"); + sb.append(" tm list\n"); + sb.append(" tm apply <PACKAGE_NAME> [-r] [-c <COMPONENT> [-c <COMPONENT>] ...]\n"); + sb.append(" tm rebuild\n"); + sb.append(" tm process <PACKAGE_NAME>\n"); + sb.append("\n"); + sb.append("tm list: return a list of theme packages.\n"); + sb.append("\n"); + sb.append("tm apply: applies the components for the theme specified by PACKAGE_NAME.\n"); + sb.append(" -r: remove per app themes\n"); + sb.append(" [-c <COMPONENT> [-c <COMPONENT>] ...]\n"); + sb.append(" if no components are specified all components will be applied.\n"); + sb.append(" Valid components are:\n"); + for (String component : components) { + sb.append(" "); + sb.append(component); + sb.append("\n"); + } + sb.append("\n"); + sb.append("tm rebuild: rebuilds the resource cache.\n"); + sb.append("\n"); + sb.append("tm process: processes the theme resources for the theme specified by " + + "PACKAGE_NAME.\n"); + + out.println(sb.toString()); + } + + public void onRun() throws Exception { + mTs = IThemeService.Stub.asInterface(ServiceManager + .getService(CMContextConstants.CM_THEME_SERVICE)); + if (mTs == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to theme service; is the system running?"); + } + + mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + if (mPm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to package manager; is the system running?"); + } + + String op = nextArgRequired(); + + if (op.equals("list")) { + runListThemePackages(); + } else if (op.equals("apply")) { + runApplyTheme(); + } else if (op.equals("rebuild")) { + runRebuildResourceCache(); + } else if (op.equals("process")) { + runProcessTheme(); + } else { + showError("Error: unknown command '" + op + "'"); + return; + } + } + + private void runListThemePackages() throws Exception { + List<PackageInfo> packages = getInstalledPackages(mPm, 0, UserHandle.USER_OWNER); + + // there is always a "system" theme available + System.out.println("package:system [theme]"); + for (PackageInfo info : packages) { + if (info.isThemeApk || info.isLegacyIconPackApk) { + System.out.print("package:"); + System.out.print(info.packageName); + if (info.isThemeApk) { + System.out.println(" [theme]"); + } else { + System.out.println(" [icon pack]"); + } + } + } + } + + private void runApplyTheme() throws Exception { + String pkgName = nextArg(); + if (pkgName == null) { + System.err.println("Error: didn't specify theme package to apply"); + return; + } + if (!SYSTEM_THEME.equals(pkgName)) { + PackageInfo info = mPm.getPackageInfo(pkgName, 0, UserHandle.USER_OWNER); + if (info == null) { + System.err.println("Error: invalid package name"); + return; + } + if (!(info.isThemeApk || info.isLegacyIconPackApk)) { + System.err.println("Error: package is not a theme or icon pack"); + return; + } + } + + boolean removePerAppThemes = false; + + ThemeChangeRequest.Builder builder = new ThemeChangeRequest.Builder(); + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-c")) { + builder.setComponent(nextArgRequired(), pkgName); + } else if (opt.equals("-r")) { + removePerAppThemes = true; + } + } + + // No components specified so let's just try and apply EVERYTHING! + Map<String, String> componentMap = builder.build().getThemeComponentsMap(); + if (componentMap.size() == 0) { + List<String> components = ThemeUtils.getAllComponents(); + for (String component : components) { + builder.setComponent(component, pkgName); + } + } + mTs.requestThemeChange(builder.build(), removePerAppThemes); + } + + private void runRebuildResourceCache() throws Exception { + mTs.rebuildResourceCache(); + } + + private void runProcessTheme() throws Exception { + String pkgName = nextArg(); + if (pkgName == null) { + System.err.println("Error: didn't specify theme package to apply"); + return; + } + PackageInfo info = mPm.getPackageInfo(pkgName, 0, UserHandle.USER_OWNER); + if (info == null) { + System.err.println("Error: invalid package name"); + return; + } + if (!info.isThemeApk) { + System.err.println("Error: package is not a theme"); + return; + } + + mTs.processThemeResources(pkgName); + } + + @SuppressWarnings("unchecked") + private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId) + throws RemoteException { + ParceledListSlice<PackageInfo> slice = pm.getInstalledPackages(flags, userId); + return slice.getList(); + } + +} diff --git a/cmds/tm/tm b/cmds/tm/tm new file mode 100755 index 0000000..dc95b6f --- /dev/null +++ b/cmds/tm/tm @@ -0,0 +1,6 @@ +# Script to start "tm" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/tm.jar +exec app_process $base/bin com.android.commands.tm.Tm "$@" |