diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d772a74d..e37efbded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * **[Breaking change]** Remove `AppCenter.setCustomProperties` API. * **[Fix]** Remove `android.support.test.InstrumentationRegistry` string that caused an error when checking applications on availability of android support libraries. +* **[Feature]** Add method to manually set the country code `AppCenter.setCountryCode(string)`. ### App Center Analytics diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java index 381ccb9cc..e235c1a04 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java @@ -121,6 +121,13 @@ static void startAppCenter(Application application, String startTypeString) { // Analytics.enableManualSessionTracker(); } + /* Set country code. */ + String countryCode = MainActivity.sSharedPreferences.getString(application.getString(R.string.country_code_key), null); + if (countryCode != null) { + // TODO uncomment after release + // AppCenter.setCountryCode(countryCode); + } + /* Set the track explicitly only if we set it in settings, to test the initial public by default at first launch. */ int savedTrack = sSharedPreferences.getInt(application.getString(R.string.appcenter_distribute_track_state_key), 0); if (savedTrack != 0) { diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java index 9626ee960..00c944315 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java @@ -107,6 +107,34 @@ public boolean isEnabled() { return AppCenter.isEnabled().get(); } }); + initClickableSetting(R.string.country_code_key, MainActivity.sSharedPreferences.getString(getActivity().getString(R.string.country_code_key), ""), new Preference.OnPreferenceClickListener() { + + @Override + public boolean onPreferenceClick(final Preference preference) { + final EditText input = new EditText(getActivity()); + input.setInputType(InputType.TYPE_CLASS_TEXT); + input.setHint(R.string.country_code_title); + input.setText(MainActivity.sSharedPreferences.getString(getActivity().getString(R.string.country_code_key), "")); + input.setSelection(input.getText().length()); + new AlertDialog.Builder(getActivity()).setTitle(R.string.storage_size_title).setView(input) + .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { + + @SuppressLint("CommitPrefEdits") + @Override + public void onClick(DialogInterface dialog, int which) { + MainActivity.sSharedPreferences + .edit() + .putString(getActivity().getString(R.string.country_code_key), input.getText().toString()) + .apply(); + preference.setSummary(input.getText()); + Toast.makeText(getActivity(), getActivity().getString(R.string.country_code_save_message), Toast.LENGTH_SHORT).show(); + } + }) + .setNegativeButton(R.string.cancel, null) + .create().show(); + return true; + } + }); initClickableSetting(R.string.storage_size_key, Formatter.formatFileSize(getActivity(), MainActivity.sSharedPreferences.getLong(MAX_STORAGE_SIZE_KEY, DEFAULT_MAX_STORAGE_SIZE)), new Preference.OnPreferenceClickListener() { @Override diff --git a/apps/sasquatch/src/main/res/values/settings.xml b/apps/sasquatch/src/main/res/values/settings.xml index c202082d0..1ee12aa7f 100644 --- a/apps/sasquatch/src/main/res/values/settings.xml +++ b/apps/sasquatch/src/main/res/values/settings.xml @@ -12,6 +12,10 @@ storage_size_key Storage Max Size + country_code_key + Country Code + Country code value will be applied after the application restart. + storage_file_size_key Storage File Size diff --git a/apps/sasquatch/src/main/res/xml/settings.xml b/apps/sasquatch/src/main/res/xml/settings.xml index 79be12162..a68dde634 100644 --- a/apps/sasquatch/src/main/res/xml/settings.xml +++ b/apps/sasquatch/src/main/res/xml/settings.xml @@ -8,6 +8,9 @@ + diff --git a/sdk/appcenter/src/main/java/com/microsoft/appcenter/AppCenter.java b/sdk/appcenter/src/main/java/com/microsoft/appcenter/AppCenter.java index d6fa46743..cae518066 100644 --- a/sdk/appcenter/src/main/java/com/microsoft/appcenter/AppCenter.java +++ b/sdk/appcenter/src/main/java/com/microsoft/appcenter/AppCenter.java @@ -288,6 +288,15 @@ public static void setLogUrl(String logUrl) { getInstance().setInstanceLogUrl(logUrl); } + /** + * Set the two-letter ISO country code to send to the backend. + * + * @param countryCode the two-letter ISO country code. See https://www.iso.org/obp/ui/#search for more information. + */ + public static void setCountryCode(String countryCode) { + DeviceInfoHelper.setCountryCode(countryCode); + } + /** * Get the current version of App Center SDK. * diff --git a/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/DeviceInfoHelper.java b/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/DeviceInfoHelper.java index d87ab9a15..d58c57ff3 100644 --- a/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/DeviceInfoHelper.java +++ b/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/DeviceInfoHelper.java @@ -17,7 +17,6 @@ import android.util.DisplayMetrics; import android.view.Display; import android.view.Surface; -import android.view.WindowManager; import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.ingestion.models.Device; @@ -41,6 +40,11 @@ public class DeviceInfoHelper { */ private static WrapperSdk sWrapperSdk; + /** + * Country code. + */ + private static String mCountryCode; + /** * Gets device information. * @@ -81,6 +85,11 @@ public static synchronized Device getDeviceInfo(Context context) throws DeviceIn AppCenterLog.error(AppCenter.LOG_TAG, "Cannot retrieve carrier info", e); } + /* Set country code. */ + if (mCountryCode != null) { + device.setCarrierCountry(mCountryCode); + } + /* Locale. */ device.setLocale(Locale.getDefault().toString()); @@ -180,6 +189,20 @@ public static synchronized void setWrapperSdk(WrapperSdk wrapperSdk) { sWrapperSdk = wrapperSdk; } + /** + * Set the two-letter ISO country code. + * + * @param countryCode the two-letter ISO country code. + */ + public static void setCountryCode(String countryCode) { + if (countryCode != null && countryCode.length() != 2) { + AppCenterLog.error(AppCenterLog.LOG_TAG, "App Center accepts only the two-letter ISO country code."); + return; + } + mCountryCode = countryCode; + AppCenterLog.debug(AppCenterLog.LOG_TAG, String.format("Set country code: %s", countryCode)); + } + /** * Thrown when {@link DeviceInfoHelper} cannot retrieve device information from devices */ diff --git a/sdk/appcenter/src/test/java/com/microsoft/appcenter/AppCenterTest.java b/sdk/appcenter/src/test/java/com/microsoft/appcenter/AppCenterTest.java index 31848f31d..b3856b33a 100644 --- a/sdk/appcenter/src/test/java/com/microsoft/appcenter/AppCenterTest.java +++ b/sdk/appcenter/src/test/java/com/microsoft/appcenter/AppCenterTest.java @@ -845,6 +845,18 @@ public void setWrapperSdkTest() { verify(mChannel).invalidateDeviceCache(); } + @Test + public void setCountryCode() { + + /* Set country code. */ + String expectedCountryCode = "aa"; + AppCenter.setCountryCode(expectedCountryCode); + + /* Check that method was called. */ + verifyStatic(); + DeviceInfoHelper.setCountryCode(eq(expectedCountryCode)); + } + @Test public void setDefaultLogLevelRelease() { mApplicationInfo.flags = 0; diff --git a/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/DeviceInfoHelperTest.java b/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/DeviceInfoHelperTest.java index 861b2883c..2c2cc15e8 100644 --- a/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/DeviceInfoHelperTest.java +++ b/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/DeviceInfoHelperTest.java @@ -84,6 +84,7 @@ public class DeviceInfoHelperTest { @Before public void setup() { + DeviceInfoHelper.setCountryCode(null); when(mContext.getPackageManager()).thenReturn(mPackageManager); } @@ -290,4 +291,76 @@ public void getDeviceInfoMissingScreenSize() throws DeviceInfoHelper.DeviceInfoE verifyStatic(); AppCenterLog.error(eq(AppCenter.LOG_TAG), anyString(), any(Exception.class)); } + + @Test + public void setCountryCode() throws DeviceInfoHelper.DeviceInfoException, PackageManager.NameNotFoundException { + + /* Mock system calls. */ + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo); + when(mTelephonyManager.getNetworkCountryIso()).thenReturn(""); + when(mTelephonyManager.getNetworkOperatorName()).thenReturn(""); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + + /* Set invalid country code. */ + String expectedCountryCode = "aa"; + DeviceInfoHelper.setCountryCode(expectedCountryCode); + + /* Get device info. */ + Device device = DeviceInfoHelper.getDeviceInfo(mContext); + assertEquals(device.getCarrierCountry(), expectedCountryCode); + } + + @Test + public void setNullCountryCode() throws DeviceInfoHelper.DeviceInfoException, PackageManager.NameNotFoundException { + + /* Mock system calls. */ + String expectedCountryCode = "aa"; + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo); + when(mTelephonyManager.getNetworkCountryIso()).thenReturn(expectedCountryCode); + when(mTelephonyManager.getNetworkOperatorName()).thenReturn(expectedCountryCode); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + + /* Set country code. */ + DeviceInfoHelper.setCountryCode(null); + + /* Verify that system method was called. */ + Device device = DeviceInfoHelper.getDeviceInfo(mContext); + verify(mTelephonyManager).getNetworkCountryIso(); + assertEquals(device.getCarrierCountry(), expectedCountryCode); + } + + @Test + public void setShortCountryCode() throws DeviceInfoHelper.DeviceInfoException, PackageManager.NameNotFoundException { + verifyCountryCodeWithInvalidLength("a"); + } + + @Test + public void setLongCountryCode() throws DeviceInfoHelper.DeviceInfoException, PackageManager.NameNotFoundException { + verifyCountryCodeWithInvalidLength("abc"); + } + + public void verifyCountryCodeWithInvalidLength(String countryCode) throws DeviceInfoHelper.DeviceInfoException, PackageManager.NameNotFoundException { + + /* Mock system calls. */ + String expectedCountryCode = "aa"; + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(mPackageInfo); + when(mTelephonyManager.getNetworkCountryIso()).thenReturn(expectedCountryCode); + when(mTelephonyManager.getNetworkOperatorName()).thenReturn(expectedCountryCode); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + + /* Mocking instances. */ + mockStatic(AppCenterLog.class); + + /* Set invalid country code. */ + DeviceInfoHelper.setCountryCode(countryCode); + + /* Verify that log was called.*/ + verifyStatic(); + AppCenterLog.error(eq(AppCenter.LOG_TAG), eq("App Center accepts only the two-letter ISO country code.")); + + /* Verify that invalid value wasn't set. */ + Device device = DeviceInfoHelper.getDeviceInfo(mContext); + assertEquals(device.getCarrierCountry(), expectedCountryCode); + verify(mTelephonyManager).getNetworkCountryIso(); + } }