Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71e7ac47 authored by Dan Pasanen's avatar Dan Pasanen
Browse files

Merge tag 'android-7.1.2_r2' into cm-14.1

Android 7.1.2 Release 2 (N2G47E)

Change-Id: I6ad99831e8b63d43e4824264bd54a5d4da3e21e3
parents 9d85a42d 6422e8fb
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -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 \
@@ -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 \
+2 −0
Original line number Original line Diff line number Diff line
@@ -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);
@@ -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);
+26 −1
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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" +
@@ -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" +
@@ -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, "");
@@ -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 + "'");
        }
        }
@@ -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;
@@ -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.
+172 −62
Original line number Original line Diff line number Diff line
@@ -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".
@@ -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.
@@ -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);
@@ -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.
@@ -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;
}
}


@@ -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];
@@ -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
@@ -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;
@@ -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) {
@@ -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)) {
@@ -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) {
@@ -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;
@@ -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;
        }
        }
@@ -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()) {
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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;
+20 −5
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -108,6 +119,7 @@ private:
        String8 audioConf;
        String8 audioConf;
        String8 fileName;
        String8 fileName;
        ZipFileRO* zip;
        ZipFileRO* zip;
        Font clockFont;
    };
    };


    /**
    /**
@@ -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;
@@ -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;
@@ -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