summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/bootanimation/Android.mk23
-rw-r--r--cmds/bootanimation/BootAnimation.cpp368
-rw-r--r--cmds/bootanimation/BootAnimation.h14
-rw-r--r--cmds/bootanimation/bootanimation_main.cpp3
-rw-r--r--cmds/idmap/create.cpp37
-rw-r--r--cmds/idmap/idmap.cpp72
-rw-r--r--cmds/idmap/idmap.h5
-rw-r--r--cmds/idmap/inspect.cpp12
-rw-r--r--cmds/idmap/scan.cpp2
-rw-r--r--cmds/input/src/com/android/commands/input/Input.java1
-rw-r--r--cmds/screencap/screencap.cpp22
-rw-r--r--cmds/tm/Android.mk15
-rw-r--r--cmds/tm/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/tm/NOTICE190
-rw-r--r--cmds/tm/src/com/android/commands/tm/Tm.java201
-rwxr-xr-xcmds/tm/tm6
16 files changed, 901 insertions, 70 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 fba462b..20c21db 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,8 @@
#include <utils/misc.h>
#include <signal.h>
#include <time.h>
+#include <pthread.h>
+#include <sys/select.h>
#include <cutils/properties.h>
@@ -54,12 +57,28 @@
#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 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 +87,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 +271,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 +336,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 +398,63 @@ 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(THEME_BOOTANIMATION_FILE, R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(THEME_BOOTANIMATION_FILE)) != 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))) {
+ ((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) {
+ // We could use readahead..
+ // ... if bionic supported it :(
+ //readahead(fd, 0, INT_MAX);
+ void *crappyBuffer = malloc(2*1024*1024);
+ if (crappyBuffer != NULL) {
+ // Read all the zip
+ while (!feof(fd))
+ fread(crappyBuffer, 1024, 2*1024, fd);
+
+ free(crappyBuffer);
+ } else {
+ ALOGW("Unable to allocate memory to preload the animation");
+ }
+ fclose(fd);
+ }
+#endif
+
return NO_ERROR;
}
@@ -452,6 +605,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,6 +710,7 @@ bool BootAnimation::movie()
mZip->endIteration(cookie);
+#ifndef CONTINUOUS_SPLASH
// clear screen
glShadeModel(GL_FLAT);
glDisable(GL_DITHER);
@@ -565,6 +720,7 @@ bool BootAnimation::movie()
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mDisplay, mSurface);
+#endif
glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
@@ -581,11 +737,46 @@ 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_cond_init(&mp_cond, NULL);
+
+ property_get("persist.sys.silent", value, "null");
+ if (strncmp(value, "1", 1) != 0) {
+ playBackgroundMusic();
+ }
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)
@@ -606,10 +797,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);
@@ -662,18 +853,169 @@ 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);
+ }
+
+ }
+
+ if (isMPlayerPrepared) {
+ ALOGD("waiting for media player to complete.");
+ struct timespec timeout;
+ clock_gettime(CLOCK_REALTIME, &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][3] = { { OEM_BOOTANIMATION_FILE,
+ SYSTEM_BOOTANIMATION_FILE,
+ SYSTEM_ENCRYPTED_BOOTANIMATION_FILE }, {
+ OEM_SHUTDOWN_ANIMATION_FILE,
+ SYSTEM_SHUTDOWN_ANIMATION_FILE,
+ SYSTEM_ENCRYPTED_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];
}
-; // namespace android
+
+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
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index f968b25..5bc1e8a 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 };
+ 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/idmap/create.cpp b/cmds/idmap/create.cpp
index 929f047..f706533 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -153,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)) {
@@ -184,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;
}
@@ -199,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)) {
@@ -211,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);
@@ -219,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 63756a5..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
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 6a6d8dc..29b9cc3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -205,7 +205,7 @@ namespace {
idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
idmap_path.append("@idmap");
- if (idmap_create_path(target_apk_path, overlay_apk_path,
+ 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());
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/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/tm/Android.mk b/cmds/tm/Android.mk
new file mode 100644
index 0000000..34a41dd
--- /dev/null
+++ b/cmds/tm/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2015 The CyanogenMod Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+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..af1ac75
--- /dev/null
+++ b/cmds/tm/src/com/android/commands/tm/Tm.java
@@ -0,0 +1,201 @@
+/*
+**
+** 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.content.pm.ThemeUtils;
+import android.content.res.IThemeService;
+import android.content.res.ThemeChangeRequest;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.AndroidException;
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+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("themes"));
+ 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 "$@"