chromium/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/WebappIcon.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.browserservices.intents;

import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.util.Base64;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;

import java.io.IOException;

/** Represents bitmap icon. Lazily converts icon format. */
public class WebappIcon {
    public static final int ICON_WITH_URL_AND_HASH_SHELL_VERSION = 169;

    private static final String TAG = "WebappIcon";

    private byte[] mUnsafeData;
    private String mEncoded;
    private Bitmap mBitmap;
    private String mWebApkPackageName;
    private int mResourceId;
    private boolean mIsTrusted;

    private String mIconUrl;
    private String mIconHash;

    public WebappIcon() {}

    public WebappIcon(byte[] unsafeData) {
        mUnsafeData = unsafeData;
    }

    /**
     * @param encoded The encoded data of a bitmap.
     * @param isTrusted Whether the encoded data came from a trusted source. If false, the data
     *     won't be used to generate a bitmap.
     */
    public WebappIcon(String encoded, boolean isTrusted) {
        mEncoded = encoded;
        mIsTrusted = isTrusted;
    }

    public WebappIcon(Bitmap bitmap) {
        mBitmap = bitmap;
    }

    public WebappIcon(String webApkPackageName, int resourceId) {
        mWebApkPackageName = webApkPackageName;
        mResourceId = resourceId;
    }

    public WebappIcon(
            String webApkPackageName, int resourceId, Resources res, int shellApkVersion) {
        mWebApkPackageName = webApkPackageName;
        mResourceId = resourceId;

        if (shellApkVersion >= ICON_WITH_URL_AND_HASH_SHELL_VERSION) {
            XmlResourceParser parser = res.getXml(mResourceId);
            try {
                int eventType = parser.getEventType();
                while (eventType != XmlPullParser.END_DOCUMENT) {
                    if (eventType == XmlPullParser.START_TAG
                            && TextUtils.equals(parser.getName(), "bitmap")) {
                        mIconUrl = parser.getAttributeValue(null, "iconUrl");
                        mIconHash = parser.getAttributeValue(null, "iconHash");
                    }
                    eventType = parser.next();
                }

            } catch (XmlPullParserException | IOException e) {
                Log.e(TAG, "Failed to parse icon XML", e);
            }
        }
    }

    public byte[] data() {
        if (mUnsafeData != null) {
            return mUnsafeData;
        }
        return Base64.decode(encoded(), Base64.DEFAULT);
    }

    public String encoded() {
        if (mEncoded == null) {
            mEncoded = BitmapHelper.encodeBitmapAsString(bitmap());
        }
        return mEncoded;
    }

    public Bitmap bitmap() {
        if (mBitmap == null) {
            mBitmap = generateBitmap();
        }
        return mBitmap;
    }

    public int resourceIdForTesting() {
        return mResourceId;
    }

    public String iconUrl() {
        return mIconUrl;
    }

    public String iconHash() {
        return mIconHash;
    }

    private Bitmap generateBitmap() {
        if (mEncoded != null && mIsTrusted) {
            return BitmapHelper.decodeBitmapFromString(mEncoded);
        }
        if (mWebApkPackageName != null && mResourceId != 0) {
            try {
                PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
                Resources res = pm.getResourcesForApplication(mWebApkPackageName);
                BitmapDrawable bitmapDrawable =
                        (BitmapDrawable) ApiCompatibilityUtils.getDrawable(res, mResourceId);
                return bitmapDrawable != null ? bitmapDrawable.getBitmap() : null;
            } catch (Exception e) {
            }
        }
        return null;
    }
}