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

Commit 9e02fbf6 authored by Josh Hou's avatar Josh Hou Committed by Android (Google) Code Review
Browse files

Merge "APP languages detection"

parents 68221b01 e19a1c68
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -972,6 +972,7 @@ package android {
    field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
    field public static final int listViewStyle = 16842868; // 0x1010074
    field public static final int listViewWhiteStyle = 16842869; // 0x1010075
    field public static final int localeConfig;
    field public static final int lockTaskMode = 16844013; // 0x10104ed
    field public static final int logo = 16843454; // 0x10102be
    field public static final int logoDescription = 16844009; // 0x10104e9
@@ -5697,6 +5698,17 @@ package android.app {
    method @Deprecated public android.view.Window startActivity(String, android.content.Intent);
  }
  public class LocaleConfig {
    ctor public LocaleConfig(@NonNull android.content.Context);
    method public int getStatus();
    method @Nullable public android.os.LocaleList getSupportedLocales();
    field public static final int STATUS_NOT_SPECIFIED = 1; // 0x1
    field public static final int STATUS_PARSING_FAILED = 2; // 0x2
    field public static final int STATUS_SUCCESS = 0; // 0x0
    field public static final String TAG_LOCALE = "locale";
    field public static final String TAG_LOCALE_CONFIG = "locale-config";
  }
  public class LocaleManager {
    method @NonNull public android.os.LocaleList getApplicationLocales();
    method public void setApplicationLocales(@NonNull android.os.LocaleList);
+166 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.LocaleList;
import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;

import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashSet;
import java.util.Set;

/**
 * The LocaleConfig of an application.
 * Defined in an XML resource file with an {@code <locale-config>} element and
 * referenced in the manifest via {@code android:localeConfig} on
 * {@code <application>}.
 *
 * For more information, see TODO(b/214154050): add link to guide
 *
 * @attr ref android.R.styleable#LocaleConfig_Locale_name
 * @attr ref android.R.styleable#AndroidManifestApplication_localeConfig
 */
public class LocaleConfig {

    private static final String TAG = "LocaleConfig";
    public static final String TAG_LOCALE_CONFIG = "locale-config";
    public static final String TAG_LOCALE = "locale";
    private LocaleList mLocales;
    private int mStatus;

    /**
     * succeeded reading the LocaleConfig structure stored in an XML file.
     */
    public static final int STATUS_SUCCESS = 0;
    /**
     * No android:localeConfig tag on <application>.
     */
    public static final int STATUS_NOT_SPECIFIED = 1;
    /**
     * Malformed input in the XML file where the LocaleConfig was stored.
     */
    public static final int STATUS_PARSING_FAILED = 2;

    /** @hide */
    @IntDef(prefix = { "STATUS_" }, value = {
            STATUS_SUCCESS,
            STATUS_NOT_SPECIFIED,
            STATUS_PARSING_FAILED
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Status{}

    /**
     * Returns the LocaleConfig for the provided application context
     *
     * @param context the context of the application
     *
     * @see Context#createPackageContext(String, int).
     */
    public LocaleConfig(@NonNull Context context) {
        int resId = 0;
        Resources res = context.getResources();
        try {
            //Get the resource id
            resId = new ApplicationInfo(context.getApplicationInfo()).getLocaleConfigRes();
            //Get the parser to read XML data
            XmlResourceParser parser = res.getXml(resId);
            parseLocaleConfig(parser, res);
        } catch (Resources.NotFoundException e) {
            Slog.w(TAG, "The resource file pointed to by the given resource ID isn't found.", e);
            mStatus = STATUS_NOT_SPECIFIED;
        } catch (XmlPullParserException | IOException e) {
            Slog.w(TAG, "Failed to parse XML configuration from "
                    + res.getResourceEntryName(resId), e);
            mStatus = STATUS_PARSING_FAILED;
        }
    }

    /**
     * Parse the XML content and get the locales supported by the application
     */
    private void parseLocaleConfig(XmlResourceParser parser, Resources res)
            throws IOException, XmlPullParserException {
        XmlUtils.beginDocument(parser, TAG_LOCALE_CONFIG);
        int outerDepth = parser.getDepth();
        AttributeSet attrs = Xml.asAttributeSet(parser);
        Set<String> localeNames = new HashSet<String>();
        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
            if (TAG_LOCALE.equals(parser.getName())) {
                final TypedArray attributes = res.obtainAttributes(
                        attrs, com.android.internal.R.styleable.LocaleConfig_Locale);
                String nameAttr = attributes.getString(
                        com.android.internal.R.styleable.LocaleConfig_Locale_name);
                localeNames.add(nameAttr);
                attributes.recycle();
            } else {
                XmlUtils.skipCurrentTag(parser);
            }
        }
        mStatus = STATUS_SUCCESS;
        mLocales = LocaleList.forLanguageTags(String.join(",", localeNames));
    }

    /**
     * Returns the locales supported by the specified application.
     *
     * <p><b>Note:</b> The locale format should follow the
     * <a href="https://www.rfc-editor.org/rfc/bcp/bcp47.txt">IETF BCP47 regular expression</a>
     *
     * @return the {@link LocaleList}
     */
    public @Nullable LocaleList getSupportedLocales() {
        return mLocales;
    }

    /**
     * Get the status of reading the resource file where the LocaleConfig was stored.
     *
     * <p>Distinguish "the application didn't provide the resource file" from "the application
     * provided malformed input" if {@link #getSupportedLocales()} returns {@code null}.
     *
     * @return {@code STATUS_SUCCESS} if the LocaleConfig structure existed in an XML file was
     * successfully read, or {@code STATUS_NOT_SPECIFIED} if no android:localeConfig tag on
     * <application> pointing to an XML file that stores the LocaleConfig, or
     * {@code STATUS_PARSING_FAILED} if the application provided malformed input for the
     * LocaleConfig structure.
     *
     * @see #STATUS_SUCCESS
     * @see #STATUS_NOT_SPECIFIED
     * @see #STATUS_PARSING_FAILED
     *
     */
    public @Status int getStatus() {
        return mStatus;
    }
}
+24 −0
Original line number Diff line number Diff line
@@ -1543,6 +1543,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    @Nullable
    private ArrayMap<String, String> mAppClassNamesByProcess;

    /**
     * Resource file providing the application's locales configuration.
     */
    private int localeConfigRes;

    public void dump(Printer pw, String prefix) {
        dump(pw, prefix, DUMP_FLAG_ALL);
    }
@@ -1660,6 +1665,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
                pw.println(prefix + "requestRawExternalStorageAccess="
                        + requestRawExternalStorageAccess);
            }
            if (localeConfigRes != 0) {
                pw.println(prefix + "localeConfigRes=0x"
                        + Integer.toHexString(localeConfigRes));
            }
        }
        pw.println(prefix + "createTimestamp=" + createTimestamp);
        super.dumpBack(pw, prefix);
@@ -1891,6 +1900,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        memtagMode = orig.memtagMode;
        nativeHeapZeroInitialized = orig.nativeHeapZeroInitialized;
        requestRawExternalStorageAccess = orig.requestRawExternalStorageAccess;
        localeConfigRes = orig.localeConfigRes;
        createTimestamp = System.currentTimeMillis();
    }

@@ -1993,6 +2003,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
                dest.writeString(mAppClassNamesByProcess.valueAt(i));
            }
        }
        dest.writeInt(localeConfigRes);
    }

    public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -2088,6 +2099,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
                mAppClassNamesByProcess.put(source.readString(), source.readString());
            }
        }
        localeConfigRes = source.readInt();
    }

    /**
@@ -2631,4 +2643,16 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        }
        return className;
    }

    /** @hide */ public void setLocaleConfigRes(int value) { localeConfigRes = value; }

    /**
     * Return the resource id pointing to the resource file that provides the application's locales
     * configuration.
     *
     * @hide
     */
    public int getLocaleConfigRes() {
        return localeConfigRes;
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -375,6 +375,8 @@ public interface ParsingPackage extends ParsingPackageRead {
    ParsingPackage setResetEnabledSettingsOnAppDataCleared(
            boolean resetEnabledSettingsOnAppDataCleared);

    ParsingPackage setLocaleConfigRes(int localeConfigRes);

    // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
    //  for moving to the next step
    @CallSuper
+16 −0
Original line number Diff line number Diff line
@@ -559,6 +559,8 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
    private UUID mStorageUuid;
    private long mLongVersionCode;

    private int mLocaleConfigRes;

    @VisibleForTesting
    public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
            @NonNull String path, @Nullable TypedArray manifestArray) {
@@ -1136,6 +1138,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
        appInfo.setSplitResourcePaths(splitCodePaths);
        appInfo.setVersionCode(mLongVersionCode);
        appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess());
        appInfo.setLocaleConfigRes(mLocaleConfigRes);

        return appInfo;
    }
@@ -1314,6 +1317,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
        dest.writeInt(this.memtagMode);
        dest.writeInt(this.nativeHeapZeroInitialized);
        sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags);
        dest.writeInt(this.mLocaleConfigRes);
    }

    public ParsingPackageImpl(Parcel in) {
@@ -1461,6 +1465,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
        this.memtagMode = in.readInt();
        this.nativeHeapZeroInitialized = in.readInt();
        this.requestRawExternalStorageAccess = sForBoolean.unparcel(in);
        this.mLocaleConfigRes = in.readInt();
        assignDerivedFields();
    }

@@ -2279,6 +2284,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
        return nativeHeapZeroInitialized;
    }

    @Override
    public int getLocaleConfigRes() {
        return mLocaleConfigRes;
    }

    @Nullable
    @Override
    public Boolean hasRequestRawExternalStorageAccess() {
@@ -2936,4 +2946,10 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
                resetEnabledSettingsOnAppDataCleared);
        return this;
    }

    @Override
    public ParsingPackageImpl setLocaleConfigRes(int value) {
        mLocaleConfigRes = value;
        return this;
    }
}
Loading