Loading Android.mk +4 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,7 @@ LOCAL_SRC_FILES += \ core/java/android/net/IIpConnectivityMetrics.aidl \ core/java/android/net/IIpConnectivityMetrics.aidl \ core/java/android/net/IEthernetManager.aidl \ core/java/android/net/IEthernetManager.aidl \ core/java/android/net/IEthernetServiceListener.aidl \ core/java/android/net/IEthernetServiceListener.aidl \ core/java/android/net/INetdEventCallback.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ Loading Loading @@ -577,6 +578,9 @@ aidl_files := \ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \ frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \ frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \ frameworks/base/core/java/android/accounts/Account.aidl \ frameworks/base/core/java/android/accounts/Account.aidl \ frameworks/base/core/java/android/app/admin/ConnectEvent.aidl \ frameworks/base/core/java/android/app/admin/DnsEvent.aidl \ frameworks/base/core/java/android/app/admin/NetworkEvent.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ frameworks/base/core/java/android/print/PageRange.aidl \ frameworks/base/core/java/android/print/PageRange.aidl \ Loading api/test-current.txt +2 −0 Original line number Original line Diff line number Diff line Loading @@ -9790,6 +9790,7 @@ package android.content.pm { method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); method public abstract boolean hasSystemFeature(java.lang.String); method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean isPermissionReviewModeEnabled(); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract boolean isSafeMode(); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); Loading Loading @@ -38217,6 +38218,7 @@ package android.test.mock { method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); method public boolean hasSystemFeature(java.lang.String); method public boolean hasSystemFeature(java.lang.String, int); method public boolean hasSystemFeature(java.lang.String, int); method public boolean isPermissionReviewModeEnabled(); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public boolean isSafeMode(); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); cmds/am/src/com/android/commands/am/Am.java +26 −1 Original line number Original line Diff line number Diff line Loading @@ -48,7 +48,9 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.pm.UserInfo; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Rect; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; Loading @@ -64,6 +66,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.text.TextUtils; import android.util.AndroidException; import android.util.AndroidException; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.view.IWindowManager; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; import com.android.internal.os.BaseCommand; Loading Loading @@ -145,7 +148,7 @@ public class Am extends BaseCommand { " am clear-debug-app\n" + " am clear-debug-app\n" + " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + " am clear-watch-heap\n" + " am clear-watch-heap\n" + " am bug-report [--progress]\n" + " am bug-report [--progress | --telephony]\n" + " am monitor [--gdb <port>]\n" + " am monitor [--gdb <port>]\n" + " am hang [--allow-restart]\n" + " am hang [--allow-restart]\n" + " am restart\n" + " am restart\n" + Loading Loading @@ -271,6 +274,7 @@ public class Am extends BaseCommand { "am bug-report: request bug report generation; will launch a notification\n" + "am bug-report: request bug report generation; will launch a notification\n" + " when done to select where it should be delivered. Options are: \n" + " when done to select where it should be delivered. Options are: \n" + " --progress: will launch a notification right away to show its progress.\n" + " --progress: will launch a notification right away to show its progress.\n" + " --telephony: will dump only telephony sections.\n" + "\n" + "\n" + "am monitor: start monitoring for crashes or ANRs.\n" + "am monitor: start monitoring for crashes or ANRs.\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + Loading Loading @@ -361,6 +365,8 @@ public class Am extends BaseCommand { "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + "\n" + "\n" + "am get-current-user: returns id of the current foreground user.\n" + "am get-current-user: returns id of the current foreground user.\n" + "\n" + "am supports-multiwindow: returns true if the device supports multiwindow.\n" + "\n" "\n" ); ); Intent.printIntentArgsHelp(pw, ""); Intent.printIntentArgsHelp(pw, ""); Loading Loading @@ -458,6 +464,8 @@ public class Am extends BaseCommand { runSendTrimMemory(); runSendTrimMemory(); } else if (op.equals("get-current-user")) { } else if (op.equals("get-current-user")) { runGetCurrentUser(); runGetCurrentUser(); } else if (op.equals("supports-multiwindow")) { runSupportsMultiwindow(); } else { } else { showError("Error: unknown command '" + op + "'"); showError("Error: unknown command '" + op + "'"); } } Loading Loading @@ -1144,6 +1152,8 @@ public class Am extends BaseCommand { while ((opt=nextOption()) != null) { while ((opt=nextOption()) != null) { if (opt.equals("--progress")) { if (opt.equals("--progress")) { bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; } else if (opt.equals("--telephony")) { bugreportType = ActivityManager.BUGREPORT_OPTION_TELEPHONY; } else { } else { System.err.println("Error: Unknown option: " + opt); System.err.println("Error: Unknown option: " + opt); return; return; Loading Loading @@ -2534,6 +2544,21 @@ public class Am extends BaseCommand { System.out.println(currentUser.id); System.out.println(currentUser.id); } } private void runSupportsMultiwindow() throws Exception { // system resources does not contain all the device configuration, construct it manually. Configuration config = mAm.getConfiguration(); if (config == null) { throw new AndroidException("Activity manager has no configuration"); } final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); Resources res = new Resources(AssetManager.getSystem(), metrics, config); System.out.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiWindow)); } /** /** * Open the given file for sending into the system process. This verifies * Open the given file for sending into the system process. This verifies * with SELinux that the system will have access to the file. * with SELinux that the system will have access to the file. Loading cmds/bootanimation/BootAnimation.cpp +172 −62 Original line number Original line Diff line number Diff line Loading @@ -71,15 +71,26 @@ static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootani static const char SYSTEM_DATA_DIR_PATH[] = "/data/system"; static const char SYSTEM_DATA_DIR_PATH[] = "/data/system"; static const char SYSTEM_TIME_DIR_NAME[] = "time"; static const char SYSTEM_TIME_DIR_NAME[] = "time"; static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time"; static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time"; static const char CLOCK_FONT_ASSET[] = "images/clock_font.png"; static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png"; static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change"; static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change"; static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change"; static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change"; static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate"; static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour"; // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00. // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00. static const long long ACCURATE_TIME_EPOCH = 946684800000; static const long long ACCURATE_TIME_EPOCH = 946684800000; static constexpr char FONT_BEGIN_CHAR = ' '; static constexpr char FONT_END_CHAR = '~' + 1; static constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1; static constexpr size_t FONT_NUM_COLS = 16; static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS; static const int TEXT_CENTER_VALUE = INT_MAX; static const int TEXT_MISSING_VALUE = INT_MIN; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; static const int ANIM_ENTRY_NAME_MAX = 256; static const int ANIM_ENTRY_NAME_MAX = 256; static constexpr size_t TEXT_POS_LEN_MAX = 16; static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; // bootreasons list in "system/core/bootstat/bootstat.cpp". // bootreasons list in "system/core/bootstat/bootstat.cpp". Loading @@ -92,7 +103,7 @@ static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST { // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeCheckThread(NULL) { mTimeFormat12Hour(false), mTimeCheckThread(NULL) { mSession = new SurfaceComposerClient(); mSession = new SurfaceComposerClient(); // If the system has already booted, the animation is not being used for a boot. // If the system has already booted, the animation is not being used for a boot. Loading Loading @@ -178,15 +189,14 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); return NO_ERROR; return NO_ERROR; } } status_t BootAnimation::initTexture(const Animation::Frame& frame) status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { { //StopWatch watch("blah"); SkBitmap bitmap; SkBitmap bitmap; SkMemoryStream stream(frame.map->getDataPtr(), frame.map->getDataLength()); SkMemoryStream stream(map->getDataPtr(), map->getDataLength()); SkImageDecoder* codec = SkImageDecoder::Factory(&stream); SkImageDecoder* codec = SkImageDecoder::Factory(&stream); if (codec != NULL) { if (codec != NULL) { codec->setDitherImage(false); codec->setDitherImage(false); Loading @@ -199,7 +209,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) // FileMap memory is never released until application exit. // FileMap memory is never released until application exit. // Release it now as the texture is already loaded and the memory used for // Release it now as the texture is already loaded and the memory used for // the packed resource can be released. // the packed resource can be released. delete frame.map; delete map; // ensure we can call getPixels(). No need to call unlock, since the // 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 will go out of scope when we return from this method. Loading Loading @@ -245,6 +255,9 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); *width = w; *height = h; return NO_ERROR; return NO_ERROR; } } Loading Loading @@ -436,7 +449,6 @@ bool BootAnimation::android() return false; return false; } } void BootAnimation::checkExit() { void BootAnimation::checkExit() { // Allow surface flinger to gracefully request shutdown // Allow surface flinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX]; Loading @@ -447,6 +459,47 @@ void BootAnimation::checkExit() { } } } } bool BootAnimation::validClock(const Animation::Part& part) { return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE; } bool parseTextCoord(const char* str, int* dest) { if (strcmp("c", str) == 0) { *dest = TEXT_CENTER_VALUE; return true; } char* end; int val = (int) strtol(str, &end, 0); if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) { return false; } *dest = val; return true; } // Parse two position coordinates. If only string is non-empty, treat it as the y value. void parsePosition(const char* str1, const char* str2, int* x, int* y) { bool success = false; if (strlen(str1) == 0) { // No values were specified // success = false } else if (strlen(str2) == 0) { // we have only one value if (parseTextCoord(str1, y)) { *x = TEXT_CENTER_VALUE; success = true; } } else { if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) { success = true; } } if (!success) { *x = TEXT_MISSING_VALUE; *y = TEXT_MISSING_VALUE; } } // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of // characters in str is a hex number in [0, 255], which are converted to // characters in str is a hex number in [0, 255], which are converted to // floating point values in the range [0.0, 1.0] and placed in the // floating point values in the range [0.0, 1.0] and placed in the Loading Loading @@ -493,69 +546,108 @@ static bool readFile(ZipFileRO* zip, const char* name, String8& outString) return true; return true; } } // The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide, // The font image should be a 96x2 array of character images. The // and the colon character is half that at 20 pixels. The glyph order is '0123456789:'. // columns are the printable ASCII characters 0x20 - 0x7f. The // We render 24 hour time. // top row is regular text; the bottom row is bold. void BootAnimation::drawTime(const Texture& clockTex, const int yPos) { status_t BootAnimation::initFont(Font* font, const char* fallback) { static constexpr char TIME_FORMAT[] = "%H:%M"; status_t status = NO_ERROR; static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT); static constexpr int DIGIT_HEIGHT = 64; if (font->map != nullptr) { static constexpr int DIGIT_WIDTH = 40; glGenTextures(1, &font->texture.name); static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2; glBindTexture(GL_TEXTURE_2D, font->texture.name); static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH; if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) { status = initTexture(font->map, &font->texture.w, &font->texture.h); ALOGE("Clock texture is too small; abandoning boot animation clock"); mClockEnabled = false; return; } time_t rawtime; glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); time(&rawtime); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); struct tm* timeInfo = localtime(&rawtime); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else if (fallback != nullptr) { status = initTexture(&font->texture, mAssets, fallback); } else { return NO_INIT; } char timeBuff[TIME_LENGTH]; if (status == NO_ERROR) { size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo); font->char_width = font->texture.w / FONT_NUM_COLS; font->char_height = font->texture.h / FONT_NUM_ROWS / 2; // There are bold and regular rows } if (length != TIME_LENGTH - 1) { return status; ALOGE("Couldn't format time; abandoning boot animation clock"); mClockEnabled = false; return; } } void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) { glEnable(GL_BLEND); // Allow us to draw on top of the animation glEnable(GL_BLEND); // Allow us to draw on top of the animation glBindTexture(GL_TEXTURE_2D, clockTex.name); glBindTexture(GL_TEXTURE_2D, font.texture.name); int xPos = (mWidth - TIME_WIDTH) / 2; const int len = strlen(str); int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT }; const int strWidth = font.char_width * len; for (int i = 0; i < TIME_LENGTH - 1; i++) { if (*x == TEXT_CENTER_VALUE) { char c = timeBuff[i]; *x = (mWidth - strWidth) / 2; int width = DIGIT_WIDTH; } else if (*x < 0) { int pos = c - '0'; // Position in the character list *x = mWidth + *x - strWidth; if (pos < 0 || pos > 10) { continue; } } if (c == ':') { if (*y == TEXT_CENTER_VALUE) { width = COLON_WIDTH; *y = (mHeight - font.char_height) / 2; } else if (*y < 0) { *y = mHeight + *y - font.char_height; } int cropRect[4] = { 0, 0, font.char_width, -font.char_height }; for (int i = 0; i < len; i++) { char c = str[i]; if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) { c = '?'; } } // Crop the texture to only the pixels in the current glyph // Crop the texture to only the pixels in the current glyph int left = pos * DIGIT_WIDTH; const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters cropRect[0] = left; const int row = charPos / FONT_NUM_COLS; cropRect[2] = width; const int col = charPos % FONT_NUM_COLS; cropRect[0] = col * font.char_width; // Left of column cropRect[1] = row * font.char_height * 2; // Top of row // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line cropRect[1] += bold ? 2 * font.char_height : font.char_height; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT); glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height); xPos += width; *x += font.char_width; } } glDisable(GL_BLEND); // Return to the animation's default behaviour glDisable(GL_BLEND); // Return to the animation's default behaviour glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0); } } // We render 12 or 24 hour time. void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) { static constexpr char TIME_FORMAT_12[] = "%l:%M"; static constexpr char TIME_FORMAT_24[] = "%H:%M"; static constexpr int TIME_LENGTH = 6; time_t rawtime; time(&rawtime); struct tm* timeInfo = localtime(&rawtime); char timeBuff[TIME_LENGTH]; const char* timeFormat = mTimeFormat12Hour ? TIME_FORMAT_12 : TIME_FORMAT_24; size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo); if (length != TIME_LENGTH - 1) { ALOGE("Couldn't format time; abandoning boot animation clock"); mClockEnabled = false; return; } char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0]; int x = xPos; int y = yPos; drawText(out, font, false, &x, &y); } bool BootAnimation::parseAnimationDesc(Animation& animation) bool BootAnimation::parseAnimationDesc(Animation& animation) { { String8 desString; String8 desString; Loading @@ -576,9 +668,10 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) int height = 0; int height = 0; int count = 0; int count = 0; int pause = 0; int pause = 0; int clockPosY = -1; char path[ANIM_ENTRY_NAME_MAX]; char path[ANIM_ENTRY_NAME_MAX]; char color[7] = "000000"; // default to black if unspecified char color[7] = "000000"; // default to black if unspecified char clockPos1[TEXT_POS_LEN_MAX + 1] = ""; char clockPos2[TEXT_POS_LEN_MAX + 1] = ""; char pathType; char pathType; if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { Loading @@ -586,15 +679,15 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) animation.width = width; animation.width = width; animation.height = height; animation.height = height; animation.fps = fps; animation.fps = fps; } else if (sscanf(l, " %c %d %d %s #%6s %d", } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s", &pathType, &count, &pause, path, color, &clockPosY) >= 4) { &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) { // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY); //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s", // pathType, count, pause, path, color, clockPos1, clockPos2); Animation::Part part; Animation::Part part; part.playUntilComplete = pathType == 'c'; part.playUntilComplete = pathType == 'c'; part.count = count; part.count = count; part.pause = pause; part.pause = pause; part.path = path; part.path = path; part.clockPosY = clockPosY; part.audioData = NULL; part.audioData = NULL; part.animation = NULL; part.animation = NULL; if (!parseColor(color, part.backgroundColor)) { if (!parseColor(color, part.backgroundColor)) { Loading @@ -603,6 +696,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) part.backgroundColor[1] = 0.0f; part.backgroundColor[1] = 0.0f; part.backgroundColor[2] = 0.0f; part.backgroundColor[2] = 0.0f; } } parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY); animation.parts.add(part); animation.parts.add(part); } } else if (strcmp(l, "$SYSTEM") == 0) { else if (strcmp(l, "$SYSTEM") == 0) { Loading Loading @@ -646,6 +740,14 @@ bool BootAnimation::preloadZip(Animation& animation) const String8 path(entryName.getPathDir()); const String8 path(entryName.getPathDir()); const String8 leaf(entryName.getPathLeaf()); const String8 leaf(entryName.getPathLeaf()); if (leaf.size() > 0) { if (leaf.size() > 0) { if (entryName == CLOCK_FONT_ZIP_NAME) { FileMap* map = zip->createEntryFileMap(entry); if (map) { animation.clockFont.map = map; } continue; } for (size_t j = 0; j < pcount; j++) { for (size_t j = 0; j < pcount; j++) { if (path == animation.parts[j].path) { if (path == animation.parts[j].path) { uint16_t method; uint16_t method; Loading Loading @@ -730,7 +832,7 @@ bool BootAnimation::movie() bool anyPartHasClock = false; bool anyPartHasClock = false; for (size_t i=0; i < animation->parts.size(); i++) { for (size_t i=0; i < animation->parts.size(); i++) { if(animation->parts[i].clockPosY >= 0) { if(validClock(animation->parts[i])) { anyPartHasClock = true; anyPartHasClock = true; break; break; } } Loading Loading @@ -768,10 +870,11 @@ bool BootAnimation::movie() glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); bool clockTextureInitialized = false; bool clockFontInitialized = false; if (mClockEnabled) { if (mClockEnabled) { clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR); clockFontInitialized = mClockEnabled = clockTextureInitialized; (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR); mClockEnabled = clockFontInitialized; } } if (mClockEnabled && !updateIsTimeAccurate()) { if (mClockEnabled && !updateIsTimeAccurate()) { Loading @@ -788,8 +891,8 @@ bool BootAnimation::movie() releaseAnimation(animation); releaseAnimation(animation); if (clockTextureInitialized) { if (clockFontInitialized) { glDeleteTextures(1, &mClock.name); glDeleteTextures(1, &animation->clockFont.texture.name); } } return false; return false; Loading Loading @@ -845,7 +948,8 @@ bool BootAnimation::playAnimation(const Animation& animation) glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } } initTexture(frame); int w, h; initTexture(frame.map, &w, &h); } } const int xc = animationX + frame.trimX; const int xc = animationX + frame.trimX; Loading @@ -867,8 +971,8 @@ bool BootAnimation::playAnimation(const Animation& animation) // which is equivalent to mHeight - (yc + frame.trimHeight) // which is equivalent to mHeight - (yc + frame.trimHeight) glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight), glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight), 0, frame.trimWidth, frame.trimHeight); 0, frame.trimWidth, frame.trimHeight); if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) { if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawTime(mClock, part.clockPosY); drawClock(animation.clockFont, part.clockPosX, part.clockPosY); } } eglSwapBuffers(mDisplay, mSurface); eglSwapBuffers(mDisplay, mSurface); Loading Loading @@ -947,6 +1051,7 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) Animation *animation = new Animation; Animation *animation = new Animation; animation->fileName = fn; animation->fileName = fn; animation->zip = zip; animation->zip = zip; animation->clockFont.map = nullptr; mLoadedFiles.add(animation->fileName); mLoadedFiles.add(animation->fileName); parseAnimationDesc(*animation); parseAnimationDesc(*animation); Loading Loading @@ -992,6 +1097,11 @@ bool BootAnimation::updateIsTimeAccurate() { } } struct stat statResult; struct stat statResult; if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) { mTimeFormat12Hour = true; } if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) { if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) { mTimeIsAccurate = true; mTimeIsAccurate = true; return true; return true; Loading cmds/bootanimation/BootAnimation.h +20 −5 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,13 @@ private: GLuint name; GLuint name; }; }; struct Font { FileMap* map; Texture texture; int char_width; int char_height; }; struct Animation { struct Animation { struct Frame { struct Frame { String8 name; String8 name; Loading @@ -90,8 +97,12 @@ private: struct Part { struct Part { int count; // The number of times this part should repeat, 0 for infinite int count; // The number of times this part should repeat, 0 for infinite int pause; // The number of frames to pause for at the end of this part int pause; // The number of frames to pause for at the end of this part int clockPosY; // The y position of the clock, in pixels, from the bottom of the int clockPosX; // The x position of the clock, in pixels. Positive values offset from // display (the clock is centred horizontally). -1 to disable the clock // the left of the screen, negative values offset from the right. int clockPosY; // The y position of the clock, in pixels. Positive values offset from // the bottom of the screen, negative values offset from the top. // If either of the above are INT_MIN the clock is disabled, if INT_MAX // the clock is centred on that axis. String8 path; String8 path; String8 trimData; String8 trimData; SortedVector<Frame> frames; SortedVector<Frame> frames; Loading @@ -108,6 +119,7 @@ private: String8 audioConf; String8 audioConf; String8 fileName; String8 fileName; ZipFileRO* zip; ZipFileRO* zip; Font clockFont; }; }; /** /** Loading @@ -118,10 +130,13 @@ private: enum ImageID { IMG_OEM = 0, IMG_SYS = 1, IMG_ENC = 2 }; enum ImageID { IMG_OEM = 0, IMG_SYS = 1, IMG_ENC = 2 }; const char *getAnimationFileName(ImageID image); const char *getAnimationFileName(ImageID image); status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(const Animation::Frame& frame); status_t initTexture(FileMap* map, int* width, int* height); status_t initFont(Font* font, const char* fallback); bool android(); bool android(); bool movie(); bool movie(); void drawTime(const Texture& clockTex, const int yPos); void drawText(const char* str, const Font& font, bool bold, int* x, int* y); void drawClock(const Font& font, const int xPos, const int yPos); bool validClock(const Animation::Part& part); Animation* loadAnimation(const String8&); Animation* loadAnimation(const String8&); bool playAnimation(const Animation&); bool playAnimation(const Animation&); void releaseAnimation(Animation*) const; void releaseAnimation(Animation*) const; Loading @@ -134,7 +149,6 @@ private: sp<SurfaceComposerClient> mSession; sp<SurfaceComposerClient> mSession; AssetManager mAssets; AssetManager mAssets; Texture mAndroid[2]; Texture mAndroid[2]; Texture mClock; int mWidth; int mWidth; int mHeight; int mHeight; bool mUseNpotTextures = false; bool mUseNpotTextures = false; Loading @@ -145,6 +159,7 @@ private: sp<Surface> mFlingerSurface; sp<Surface> mFlingerSurface; bool mClockEnabled; bool mClockEnabled; bool mTimeIsAccurate; bool mTimeIsAccurate; bool mTimeFormat12Hour; bool mSystemBoot; bool mSystemBoot; String8 mZipFileName; String8 mZipFileName; SortedVector<String8> mLoadedFiles; SortedVector<String8> mLoadedFiles; Loading Loading
Android.mk +4 −0 Original line number Original line Diff line number Diff line Loading @@ -203,6 +203,7 @@ LOCAL_SRC_FILES += \ core/java/android/net/IIpConnectivityMetrics.aidl \ core/java/android/net/IIpConnectivityMetrics.aidl \ core/java/android/net/IEthernetManager.aidl \ core/java/android/net/IEthernetManager.aidl \ core/java/android/net/IEthernetServiceListener.aidl \ core/java/android/net/IEthernetServiceListener.aidl \ core/java/android/net/INetdEventCallback.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyListener.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ core/java/android/net/INetworkPolicyManager.aidl \ Loading Loading @@ -577,6 +578,9 @@ aidl_files := \ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \ frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \ frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \ frameworks/base/core/java/android/accounts/Account.aidl \ frameworks/base/core/java/android/accounts/Account.aidl \ frameworks/base/core/java/android/app/admin/ConnectEvent.aidl \ frameworks/base/core/java/android/app/admin/DnsEvent.aidl \ frameworks/base/core/java/android/app/admin/NetworkEvent.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ frameworks/base/core/java/android/print/PageRange.aidl \ frameworks/base/core/java/android/print/PageRange.aidl \ Loading
api/test-current.txt +2 −0 Original line number Original line Diff line number Diff line Loading @@ -9790,6 +9790,7 @@ package android.content.pm { method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); method public abstract boolean hasSystemFeature(java.lang.String); method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean hasSystemFeature(java.lang.String, int); method public abstract boolean isPermissionReviewModeEnabled(); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public abstract boolean isSafeMode(); method public abstract boolean isSafeMode(); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); Loading Loading @@ -38217,6 +38218,7 @@ package android.test.mock { method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); method public boolean hasSystemFeature(java.lang.String); method public boolean hasSystemFeature(java.lang.String, int); method public boolean hasSystemFeature(java.lang.String, int); method public boolean isPermissionReviewModeEnabled(); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String); method public boolean isSafeMode(); method public boolean isSafeMode(); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int); method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
cmds/am/src/com/android/commands/am/Am.java +26 −1 Original line number Original line Diff line number Diff line Loading @@ -48,7 +48,9 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.pm.UserInfo; import android.content.res.AssetManager; import android.content.res.Configuration; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.Rect; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; Loading @@ -64,6 +66,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.text.TextUtils; import android.util.AndroidException; import android.util.AndroidException; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.view.IWindowManager; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; import com.android.internal.os.BaseCommand; Loading Loading @@ -145,7 +148,7 @@ public class Am extends BaseCommand { " am clear-debug-app\n" + " am clear-debug-app\n" + " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + " am set-watch-heap <PROCESS> <MEM-LIMIT>\n" + " am clear-watch-heap\n" + " am clear-watch-heap\n" + " am bug-report [--progress]\n" + " am bug-report [--progress | --telephony]\n" + " am monitor [--gdb <port>]\n" + " am monitor [--gdb <port>]\n" + " am hang [--allow-restart]\n" + " am hang [--allow-restart]\n" + " am restart\n" + " am restart\n" + Loading Loading @@ -271,6 +274,7 @@ public class Am extends BaseCommand { "am bug-report: request bug report generation; will launch a notification\n" + "am bug-report: request bug report generation; will launch a notification\n" + " when done to select where it should be delivered. Options are: \n" + " when done to select where it should be delivered. Options are: \n" + " --progress: will launch a notification right away to show its progress.\n" + " --progress: will launch a notification right away to show its progress.\n" + " --telephony: will dump only telephony sections.\n" + "\n" + "\n" + "am monitor: start monitoring for crashes or ANRs.\n" + "am monitor: start monitoring for crashes or ANRs.\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + Loading Loading @@ -361,6 +365,8 @@ public class Am extends BaseCommand { "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" + "\n" + "\n" + "am get-current-user: returns id of the current foreground user.\n" + "am get-current-user: returns id of the current foreground user.\n" + "\n" + "am supports-multiwindow: returns true if the device supports multiwindow.\n" + "\n" "\n" ); ); Intent.printIntentArgsHelp(pw, ""); Intent.printIntentArgsHelp(pw, ""); Loading Loading @@ -458,6 +464,8 @@ public class Am extends BaseCommand { runSendTrimMemory(); runSendTrimMemory(); } else if (op.equals("get-current-user")) { } else if (op.equals("get-current-user")) { runGetCurrentUser(); runGetCurrentUser(); } else if (op.equals("supports-multiwindow")) { runSupportsMultiwindow(); } else { } else { showError("Error: unknown command '" + op + "'"); showError("Error: unknown command '" + op + "'"); } } Loading Loading @@ -1144,6 +1152,8 @@ public class Am extends BaseCommand { while ((opt=nextOption()) != null) { while ((opt=nextOption()) != null) { if (opt.equals("--progress")) { if (opt.equals("--progress")) { bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; } else if (opt.equals("--telephony")) { bugreportType = ActivityManager.BUGREPORT_OPTION_TELEPHONY; } else { } else { System.err.println("Error: Unknown option: " + opt); System.err.println("Error: Unknown option: " + opt); return; return; Loading Loading @@ -2534,6 +2544,21 @@ public class Am extends BaseCommand { System.out.println(currentUser.id); System.out.println(currentUser.id); } } private void runSupportsMultiwindow() throws Exception { // system resources does not contain all the device configuration, construct it manually. Configuration config = mAm.getConfiguration(); if (config == null) { throw new AndroidException("Activity manager has no configuration"); } final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); Resources res = new Resources(AssetManager.getSystem(), metrics, config); System.out.println(res.getBoolean(com.android.internal.R.bool.config_supportsMultiWindow)); } /** /** * Open the given file for sending into the system process. This verifies * Open the given file for sending into the system process. This verifies * with SELinux that the system will have access to the file. * with SELinux that the system will have access to the file. Loading
cmds/bootanimation/BootAnimation.cpp +172 −62 Original line number Original line Diff line number Diff line Loading @@ -71,15 +71,26 @@ static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootani static const char SYSTEM_DATA_DIR_PATH[] = "/data/system"; static const char SYSTEM_DATA_DIR_PATH[] = "/data/system"; static const char SYSTEM_TIME_DIR_NAME[] = "time"; static const char SYSTEM_TIME_DIR_NAME[] = "time"; static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time"; static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time"; static const char CLOCK_FONT_ASSET[] = "images/clock_font.png"; static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png"; static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change"; static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change"; static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change"; static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change"; static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate"; static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate"; static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour"; // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00. // Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00. static const long long ACCURATE_TIME_EPOCH = 946684800000; static const long long ACCURATE_TIME_EPOCH = 946684800000; static constexpr char FONT_BEGIN_CHAR = ' '; static constexpr char FONT_END_CHAR = '~' + 1; static constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1; static constexpr size_t FONT_NUM_COLS = 16; static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS; static const int TEXT_CENTER_VALUE = INT_MAX; static const int TEXT_MISSING_VALUE = INT_MIN; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound"; static const int ANIM_ENTRY_NAME_MAX = 256; static const int ANIM_ENTRY_NAME_MAX = 256; static constexpr size_t TEXT_POS_LEN_MAX = 16; static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed"; static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason"; // bootreasons list in "system/core/bootstat/bootstat.cpp". // bootreasons list in "system/core/bootstat/bootstat.cpp". Loading @@ -92,7 +103,7 @@ static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST { // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeCheckThread(NULL) { mTimeFormat12Hour(false), mTimeCheckThread(NULL) { mSession = new SurfaceComposerClient(); mSession = new SurfaceComposerClient(); // If the system has already booted, the animation is not being used for a boot. // If the system has already booted, the animation is not being used for a boot. Loading Loading @@ -178,15 +189,14 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); return NO_ERROR; return NO_ERROR; } } status_t BootAnimation::initTexture(const Animation::Frame& frame) status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { { //StopWatch watch("blah"); SkBitmap bitmap; SkBitmap bitmap; SkMemoryStream stream(frame.map->getDataPtr(), frame.map->getDataLength()); SkMemoryStream stream(map->getDataPtr(), map->getDataLength()); SkImageDecoder* codec = SkImageDecoder::Factory(&stream); SkImageDecoder* codec = SkImageDecoder::Factory(&stream); if (codec != NULL) { if (codec != NULL) { codec->setDitherImage(false); codec->setDitherImage(false); Loading @@ -199,7 +209,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) // FileMap memory is never released until application exit. // FileMap memory is never released until application exit. // Release it now as the texture is already loaded and the memory used for // Release it now as the texture is already loaded and the memory used for // the packed resource can be released. // the packed resource can be released. delete frame.map; delete map; // ensure we can call getPixels(). No need to call unlock, since the // 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 will go out of scope when we return from this method. Loading Loading @@ -245,6 +255,9 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame) glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); *width = w; *height = h; return NO_ERROR; return NO_ERROR; } } Loading Loading @@ -436,7 +449,6 @@ bool BootAnimation::android() return false; return false; } } void BootAnimation::checkExit() { void BootAnimation::checkExit() { // Allow surface flinger to gracefully request shutdown // Allow surface flinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; char value[PROPERTY_VALUE_MAX]; Loading @@ -447,6 +459,47 @@ void BootAnimation::checkExit() { } } } } bool BootAnimation::validClock(const Animation::Part& part) { return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE; } bool parseTextCoord(const char* str, int* dest) { if (strcmp("c", str) == 0) { *dest = TEXT_CENTER_VALUE; return true; } char* end; int val = (int) strtol(str, &end, 0); if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) { return false; } *dest = val; return true; } // Parse two position coordinates. If only string is non-empty, treat it as the y value. void parsePosition(const char* str1, const char* str2, int* x, int* y) { bool success = false; if (strlen(str1) == 0) { // No values were specified // success = false } else if (strlen(str2) == 0) { // we have only one value if (parseTextCoord(str1, y)) { *x = TEXT_CENTER_VALUE; success = true; } } else { if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) { success = true; } } if (!success) { *x = TEXT_MISSING_VALUE; *y = TEXT_MISSING_VALUE; } } // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of // Parse a color represented as an HTML-style 'RRGGBB' string: each pair of // characters in str is a hex number in [0, 255], which are converted to // characters in str is a hex number in [0, 255], which are converted to // floating point values in the range [0.0, 1.0] and placed in the // floating point values in the range [0.0, 1.0] and placed in the Loading Loading @@ -493,69 +546,108 @@ static bool readFile(ZipFileRO* zip, const char* name, String8& outString) return true; return true; } } // The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide, // The font image should be a 96x2 array of character images. The // and the colon character is half that at 20 pixels. The glyph order is '0123456789:'. // columns are the printable ASCII characters 0x20 - 0x7f. The // We render 24 hour time. // top row is regular text; the bottom row is bold. void BootAnimation::drawTime(const Texture& clockTex, const int yPos) { status_t BootAnimation::initFont(Font* font, const char* fallback) { static constexpr char TIME_FORMAT[] = "%H:%M"; status_t status = NO_ERROR; static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT); static constexpr int DIGIT_HEIGHT = 64; if (font->map != nullptr) { static constexpr int DIGIT_WIDTH = 40; glGenTextures(1, &font->texture.name); static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2; glBindTexture(GL_TEXTURE_2D, font->texture.name); static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH; if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) { status = initTexture(font->map, &font->texture.w, &font->texture.h); ALOGE("Clock texture is too small; abandoning boot animation clock"); mClockEnabled = false; return; } time_t rawtime; glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); time(&rawtime); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); struct tm* timeInfo = localtime(&rawtime); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else if (fallback != nullptr) { status = initTexture(&font->texture, mAssets, fallback); } else { return NO_INIT; } char timeBuff[TIME_LENGTH]; if (status == NO_ERROR) { size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo); font->char_width = font->texture.w / FONT_NUM_COLS; font->char_height = font->texture.h / FONT_NUM_ROWS / 2; // There are bold and regular rows } if (length != TIME_LENGTH - 1) { return status; ALOGE("Couldn't format time; abandoning boot animation clock"); mClockEnabled = false; return; } } void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) { glEnable(GL_BLEND); // Allow us to draw on top of the animation glEnable(GL_BLEND); // Allow us to draw on top of the animation glBindTexture(GL_TEXTURE_2D, clockTex.name); glBindTexture(GL_TEXTURE_2D, font.texture.name); int xPos = (mWidth - TIME_WIDTH) / 2; const int len = strlen(str); int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT }; const int strWidth = font.char_width * len; for (int i = 0; i < TIME_LENGTH - 1; i++) { if (*x == TEXT_CENTER_VALUE) { char c = timeBuff[i]; *x = (mWidth - strWidth) / 2; int width = DIGIT_WIDTH; } else if (*x < 0) { int pos = c - '0'; // Position in the character list *x = mWidth + *x - strWidth; if (pos < 0 || pos > 10) { continue; } } if (c == ':') { if (*y == TEXT_CENTER_VALUE) { width = COLON_WIDTH; *y = (mHeight - font.char_height) / 2; } else if (*y < 0) { *y = mHeight + *y - font.char_height; } int cropRect[4] = { 0, 0, font.char_width, -font.char_height }; for (int i = 0; i < len; i++) { char c = str[i]; if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) { c = '?'; } } // Crop the texture to only the pixels in the current glyph // Crop the texture to only the pixels in the current glyph int left = pos * DIGIT_WIDTH; const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters cropRect[0] = left; const int row = charPos / FONT_NUM_COLS; cropRect[2] = width; const int col = charPos % FONT_NUM_COLS; cropRect[0] = col * font.char_width; // Left of column cropRect[1] = row * font.char_height * 2; // Top of row // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line cropRect[1] += bold ? 2 * font.char_height : font.char_height; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect); glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT); glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height); xPos += width; *x += font.char_width; } } glDisable(GL_BLEND); // Return to the animation's default behaviour glDisable(GL_BLEND); // Return to the animation's default behaviour glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0); } } // We render 12 or 24 hour time. void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) { static constexpr char TIME_FORMAT_12[] = "%l:%M"; static constexpr char TIME_FORMAT_24[] = "%H:%M"; static constexpr int TIME_LENGTH = 6; time_t rawtime; time(&rawtime); struct tm* timeInfo = localtime(&rawtime); char timeBuff[TIME_LENGTH]; const char* timeFormat = mTimeFormat12Hour ? TIME_FORMAT_12 : TIME_FORMAT_24; size_t length = strftime(timeBuff, TIME_LENGTH, timeFormat, timeInfo); if (length != TIME_LENGTH - 1) { ALOGE("Couldn't format time; abandoning boot animation clock"); mClockEnabled = false; return; } char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0]; int x = xPos; int y = yPos; drawText(out, font, false, &x, &y); } bool BootAnimation::parseAnimationDesc(Animation& animation) bool BootAnimation::parseAnimationDesc(Animation& animation) { { String8 desString; String8 desString; Loading @@ -576,9 +668,10 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) int height = 0; int height = 0; int count = 0; int count = 0; int pause = 0; int pause = 0; int clockPosY = -1; char path[ANIM_ENTRY_NAME_MAX]; char path[ANIM_ENTRY_NAME_MAX]; char color[7] = "000000"; // default to black if unspecified char color[7] = "000000"; // default to black if unspecified char clockPos1[TEXT_POS_LEN_MAX + 1] = ""; char clockPos2[TEXT_POS_LEN_MAX + 1] = ""; char pathType; char pathType; if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { Loading @@ -586,15 +679,15 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) animation.width = width; animation.width = width; animation.height = height; animation.height = height; animation.fps = fps; animation.fps = fps; } else if (sscanf(l, " %c %d %d %s #%6s %d", } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s", &pathType, &count, &pause, path, color, &clockPosY) >= 4) { &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) { // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY); //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s", // pathType, count, pause, path, color, clockPos1, clockPos2); Animation::Part part; Animation::Part part; part.playUntilComplete = pathType == 'c'; part.playUntilComplete = pathType == 'c'; part.count = count; part.count = count; part.pause = pause; part.pause = pause; part.path = path; part.path = path; part.clockPosY = clockPosY; part.audioData = NULL; part.audioData = NULL; part.animation = NULL; part.animation = NULL; if (!parseColor(color, part.backgroundColor)) { if (!parseColor(color, part.backgroundColor)) { Loading @@ -603,6 +696,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) part.backgroundColor[1] = 0.0f; part.backgroundColor[1] = 0.0f; part.backgroundColor[2] = 0.0f; part.backgroundColor[2] = 0.0f; } } parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY); animation.parts.add(part); animation.parts.add(part); } } else if (strcmp(l, "$SYSTEM") == 0) { else if (strcmp(l, "$SYSTEM") == 0) { Loading Loading @@ -646,6 +740,14 @@ bool BootAnimation::preloadZip(Animation& animation) const String8 path(entryName.getPathDir()); const String8 path(entryName.getPathDir()); const String8 leaf(entryName.getPathLeaf()); const String8 leaf(entryName.getPathLeaf()); if (leaf.size() > 0) { if (leaf.size() > 0) { if (entryName == CLOCK_FONT_ZIP_NAME) { FileMap* map = zip->createEntryFileMap(entry); if (map) { animation.clockFont.map = map; } continue; } for (size_t j = 0; j < pcount; j++) { for (size_t j = 0; j < pcount; j++) { if (path == animation.parts[j].path) { if (path == animation.parts[j].path) { uint16_t method; uint16_t method; Loading Loading @@ -730,7 +832,7 @@ bool BootAnimation::movie() bool anyPartHasClock = false; bool anyPartHasClock = false; for (size_t i=0; i < animation->parts.size(); i++) { for (size_t i=0; i < animation->parts.size(); i++) { if(animation->parts[i].clockPosY >= 0) { if(validClock(animation->parts[i])) { anyPartHasClock = true; anyPartHasClock = true; break; break; } } Loading Loading @@ -768,10 +870,11 @@ bool BootAnimation::movie() glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); bool clockTextureInitialized = false; bool clockFontInitialized = false; if (mClockEnabled) { if (mClockEnabled) { clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR); clockFontInitialized = mClockEnabled = clockTextureInitialized; (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR); mClockEnabled = clockFontInitialized; } } if (mClockEnabled && !updateIsTimeAccurate()) { if (mClockEnabled && !updateIsTimeAccurate()) { Loading @@ -788,8 +891,8 @@ bool BootAnimation::movie() releaseAnimation(animation); releaseAnimation(animation); if (clockTextureInitialized) { if (clockFontInitialized) { glDeleteTextures(1, &mClock.name); glDeleteTextures(1, &animation->clockFont.texture.name); } } return false; return false; Loading Loading @@ -845,7 +948,8 @@ bool BootAnimation::playAnimation(const Animation& animation) glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } } initTexture(frame); int w, h; initTexture(frame.map, &w, &h); } } const int xc = animationX + frame.trimX; const int xc = animationX + frame.trimX; Loading @@ -867,8 +971,8 @@ bool BootAnimation::playAnimation(const Animation& animation) // which is equivalent to mHeight - (yc + frame.trimHeight) // which is equivalent to mHeight - (yc + frame.trimHeight) glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight), glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight), 0, frame.trimWidth, frame.trimHeight); 0, frame.trimWidth, frame.trimHeight); if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) { if (mClockEnabled && mTimeIsAccurate && validClock(part)) { drawTime(mClock, part.clockPosY); drawClock(animation.clockFont, part.clockPosX, part.clockPosY); } } eglSwapBuffers(mDisplay, mSurface); eglSwapBuffers(mDisplay, mSurface); Loading Loading @@ -947,6 +1051,7 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) Animation *animation = new Animation; Animation *animation = new Animation; animation->fileName = fn; animation->fileName = fn; animation->zip = zip; animation->zip = zip; animation->clockFont.map = nullptr; mLoadedFiles.add(animation->fileName); mLoadedFiles.add(animation->fileName); parseAnimationDesc(*animation); parseAnimationDesc(*animation); Loading Loading @@ -992,6 +1097,11 @@ bool BootAnimation::updateIsTimeAccurate() { } } struct stat statResult; struct stat statResult; if(stat(TIME_FORMAT_12_HOUR_FLAG_FILE_PATH, &statResult) == 0) { mTimeFormat12Hour = true; } if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) { if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) { mTimeIsAccurate = true; mTimeIsAccurate = true; return true; return true; Loading
cmds/bootanimation/BootAnimation.h +20 −5 Original line number Original line Diff line number Diff line Loading @@ -74,6 +74,13 @@ private: GLuint name; GLuint name; }; }; struct Font { FileMap* map; Texture texture; int char_width; int char_height; }; struct Animation { struct Animation { struct Frame { struct Frame { String8 name; String8 name; Loading @@ -90,8 +97,12 @@ private: struct Part { struct Part { int count; // The number of times this part should repeat, 0 for infinite int count; // The number of times this part should repeat, 0 for infinite int pause; // The number of frames to pause for at the end of this part int pause; // The number of frames to pause for at the end of this part int clockPosY; // The y position of the clock, in pixels, from the bottom of the int clockPosX; // The x position of the clock, in pixels. Positive values offset from // display (the clock is centred horizontally). -1 to disable the clock // the left of the screen, negative values offset from the right. int clockPosY; // The y position of the clock, in pixels. Positive values offset from // the bottom of the screen, negative values offset from the top. // If either of the above are INT_MIN the clock is disabled, if INT_MAX // the clock is centred on that axis. String8 path; String8 path; String8 trimData; String8 trimData; SortedVector<Frame> frames; SortedVector<Frame> frames; Loading @@ -108,6 +119,7 @@ private: String8 audioConf; String8 audioConf; String8 fileName; String8 fileName; ZipFileRO* zip; ZipFileRO* zip; Font clockFont; }; }; /** /** Loading @@ -118,10 +130,13 @@ private: enum ImageID { IMG_OEM = 0, IMG_SYS = 1, IMG_ENC = 2 }; enum ImageID { IMG_OEM = 0, IMG_SYS = 1, IMG_ENC = 2 }; const char *getAnimationFileName(ImageID image); const char *getAnimationFileName(ImageID image); status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(const Animation::Frame& frame); status_t initTexture(FileMap* map, int* width, int* height); status_t initFont(Font* font, const char* fallback); bool android(); bool android(); bool movie(); bool movie(); void drawTime(const Texture& clockTex, const int yPos); void drawText(const char* str, const Font& font, bool bold, int* x, int* y); void drawClock(const Font& font, const int xPos, const int yPos); bool validClock(const Animation::Part& part); Animation* loadAnimation(const String8&); Animation* loadAnimation(const String8&); bool playAnimation(const Animation&); bool playAnimation(const Animation&); void releaseAnimation(Animation*) const; void releaseAnimation(Animation*) const; Loading @@ -134,7 +149,6 @@ private: sp<SurfaceComposerClient> mSession; sp<SurfaceComposerClient> mSession; AssetManager mAssets; AssetManager mAssets; Texture mAndroid[2]; Texture mAndroid[2]; Texture mClock; int mWidth; int mWidth; int mHeight; int mHeight; bool mUseNpotTextures = false; bool mUseNpotTextures = false; Loading @@ -145,6 +159,7 @@ private: sp<Surface> mFlingerSurface; sp<Surface> mFlingerSurface; bool mClockEnabled; bool mClockEnabled; bool mTimeIsAccurate; bool mTimeIsAccurate; bool mTimeFormat12Hour; bool mSystemBoot; bool mSystemBoot; String8 mZipFileName; String8 mZipFileName; SortedVector<String8> mLoadedFiles; SortedVector<String8> mLoadedFiles; Loading