/* * Copyright (C) 2022 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.net.wifi; import android.content.Context; import android.content.res.Resources; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; /** * Provide a wrapper to reading string overlay resources for WiFi. * * Specifically intended to provide a mechanism to store and read carrier-specific translatable * string overlays. Carrier-specific (MVNO) overlays are not supported - but Carrier Configurations * which do support MVNOs do not support translatable strings. * * Structure: * EAP authentication error 32760 * * :::1234:::EAP error 32760 for carrier 1234 * :::5678:::EAP error 32760 for carrier 5678 * … * * * The WiFi-stack specific solution is to store the strings in the general name-space with a known * prefix. * * @hide */ public class WifiStringResourceWrapper { private static final String TAG = "WifiStringResourceWrapper"; private final WifiContext mContext; private final int mSubId; private final int mCarrierId; private Resources mResources; private final String mCarrierIdPrefix; @VisibleForTesting static final String CARRIER_ID_RESOURCE_NAME_SUFFIX = "_carrier_overrides"; @VisibleForTesting static final String CARRIER_ID_RESOURCE_SEPARATOR = ":::"; /** * @param context a WifiContext * @param subId the sub ID to use for all the resources (overlays or carrier ID) */ public WifiStringResourceWrapper(WifiContext context, int subId, int carrierId) { mContext = context; mSubId = subId; mCarrierId = carrierId; mCarrierIdPrefix = CARRIER_ID_RESOURCE_SEPARATOR + mCarrierId + CARRIER_ID_RESOURCE_SEPARATOR; } /** * Returns the string corresponding to the resource ID - or null if no resources exist. */ public String getString(String name, Object... args) { if (getResourcesForSubId() == null) return null; int resourceId = mResources.getIdentifier(name, "string", mContext.getWifiOverlayApkPkgName()); if (resourceId == 0) return null; // check if there's a carrier-specific override array if (mCarrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { String carrierOverrideString = getCarrierOverrideString(name, args); if (carrierOverrideString != null) { return carrierOverrideString; } } try { return mResources.getString(resourceId, args); } catch (java.util.IllegalFormatException e) { Log.e(TAG, "Resource formatting error - '" + name + "' - " + e); return null; } } /** * Returns the int corresponding to the resource ID - or the default value if no resources * exist. */ public int getInt(String name, int defaultValue) { if (getResourcesForSubId() == null) return defaultValue; int resourceId = mResources.getIdentifier(name, "integer", mContext.getWifiOverlayApkPkgName()); if (resourceId == 0) return defaultValue; // check if there's a carrier-specific override array if (mCarrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { String carrierOverrideString = getCarrierOverrideString(name); if (carrierOverrideString != null) { try { return Integer.parseInt(carrierOverrideString); } catch (Exception e) { Log.e(TAG, "Failed to parse String into int. String=" + carrierOverrideString); } } } return mResources.getInteger(resourceId); } /** * Returns the boolean corresponding to the resource ID - or the default value if no resources * exist. */ public boolean getBoolean(String name, boolean defaultValue) { if (getResourcesForSubId() == null) return defaultValue; int resourceId = mResources.getIdentifier(name, "bool", mContext.getWifiOverlayApkPkgName()); if (resourceId == 0) return defaultValue; // check if there's a carrier-specific override array if (mCarrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { String carrierOverrideString = getCarrierOverrideString(name); if (carrierOverrideString != null) { try { return Boolean.parseBoolean(carrierOverrideString); } catch (Exception e) { Log.e(TAG, "Failed to parse String into boolean. String=" + carrierOverrideString); } } } return mResources.getBoolean(resourceId); } /** * Return the String resource override by the carrier, or null if no override is found. */ private String getCarrierOverrideString(String name, Object... args) { int arrayResourceId = mResources.getIdentifier(name + CARRIER_ID_RESOURCE_NAME_SUFFIX, "array", mContext.getWifiOverlayApkPkgName()); if (arrayResourceId != 0) { String[] carrierIdOverlays = mResources.getStringArray(arrayResourceId); // check for the :::carrier-id::: prefix and if exists format and return it for (String carrierIdOverlay : carrierIdOverlays) { if (carrierIdOverlay.indexOf(mCarrierIdPrefix) != 0) continue; try { return String.format(carrierIdOverlay.substring(mCarrierIdPrefix.length()), args); } catch (java.util.IllegalFormatException e) { Log.e(TAG, "Resource formatting error - '" + name + "' - " + e); return null; } } } return null; } /** * Returns the resources from the given context for the MCC/MNC * associated with the subscription. */ private Resources getResourcesForSubId() { if (mResources != null) { return mResources; } Context context = mContext.getResourcesApkContext(); if (context == null) { return null; } mResources = SubscriptionManager.getResourcesForSubId(context, mSubId); return mResources; } }