Skip to content

Commit

Permalink
Merge pull request #1708 from microsoft/develop
Browse files Browse the repository at this point in the history
Version 5.0.3
  • Loading branch information
AnatolyPristensky committed Sep 20, 2023
2 parents de8553f + 46e6bf2 commit 7fffffe
Show file tree
Hide file tree
Showing 18 changed files with 318 additions and 16 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# App Center SDK for Android Change Log

## Version 5.0.2 (In development)
## Version 5.0.3 (In development)

## Version 5.0.2

### AppCenter

Expand Down
6 changes: 3 additions & 3 deletions apps/sasquatch/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
flavorDimensions "dependency", "distribute"

defaultConfig {
versionCode 300
versionName "5.0.1"
versionCode 302
versionName "5.0.3"
externalNativeBuild {
ndkBuild {
arguments "NDK_APPLICATION_MK=Application.mk", "V=1"
Expand Down Expand Up @@ -100,7 +100,7 @@ dependencies {
projectDependencyImplementation project(':sdk:appcenter-analytics')
projectDependencyImplementation project(':sdk:appcenter-crashes')

def appCenterSdkVersion = "5.0.1"
def appCenterSdkVersion = "5.0.2"
mavenCentralDependencyImplementation "com.microsoft.appcenter:appcenter-analytics:${appCenterSdkVersion}"
mavenCentralDependencyImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ static void startAppCenter(Application application, String startTypeString) {
AppCenter.setCountryCode(countryCode);
}

// TODO: uncomment this code after release sdk to maven
// /* Set data residency region. */
// String dataResidencyRegion = MainActivity.sSharedPreferences.getString(application.getString(R.string.data_residency_region_key), null);
// if (dataResidencyRegion != null) {
// AppCenter.setDataResidencyRegion(dataResidencyRegion);
// }

/* 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,34 @@ public void onClick(DialogInterface dialog, int which) {
return true;
}
});
initClickableSetting(R.string.data_residency_region_key, MainActivity.sSharedPreferences.getString(getActivity().getString(R.string.data_residency_region_key), null), 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.data_residency_region_title);
input.setText(MainActivity.sSharedPreferences.getString(getActivity().getString(R.string.data_residency_region_key), null));
input.setSelection(input.getText().length());
new AlertDialog.Builder(getActivity()).setTitle(R.string.data_residency_region_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.data_residency_region_key), input.getText().toString())
.apply();
preference.setSummary(input.getText());
Toast.makeText(getActivity(), getActivity().getString(R.string.data_residency_region_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
Expand Down
4 changes: 4 additions & 0 deletions apps/sasquatch/src/main/res/values/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<string name="country_code_title" tools:ignore="MissingTranslation">Country Code</string>
<string name="country_code_save_message" tools:ignore="MissingTranslation">Country code value will be applied after the application restart.</string>

<string name="data_residency_region_key" tools:ignore="MissingTranslation">data_residency_region</string>
<string name="data_residency_region_title" tools:ignore="MissingTranslation">Data residency region</string>
<string name="data_residency_region_save_message" tools:ignore="MissingTranslation">Data residency region value will be applied after the application restart.</string>

<string name="storage_file_size_key" tools:ignore="MissingTranslation">storage_file_size_key</string>
<string name="storage_file_size_title" tools:ignore="MissingTranslation">Storage File Size</string>

Expand Down
5 changes: 5 additions & 0 deletions apps/sasquatch/src/main/res/xml/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
<Preference
android:key="@string/country_code_key"
android:title="@string/country_code_title" />
<EditTextPreference
android:key="@string/data_residency_region_key"
android:selectAllOnFocus="false"
android:singleLine="false"
android:title="@string/data_residency_region_title" />
<Preference
android:key="@string/storage_size_key"
android:title="@string/storage_size_title" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

package com.microsoft.appcenter.crashes.utils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import androidx.test.platform.app.InstrumentationRegistry;

import com.microsoft.appcenter.Constants;
Expand All @@ -19,12 +25,6 @@
import java.io.File;
import java.util.UUID;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

@SuppressWarnings("unused")
public class ErrorLogHelperAndroidTest {

Expand Down Expand Up @@ -170,4 +170,19 @@ public void parseDevice() {
assertNotNull(device4);
assertNull(userId4);
}

@Test
public void parseDataResidencyRegion() {
String mockDataResidencyRegion = "mockRegion";
String mockContextInformation = "{\"dataResidencyRegion\":\"" + mockDataResidencyRegion + "\"}";
String result = ErrorLogHelper.parseDataResidencyRegion(mockContextInformation);
assertEquals(mockDataResidencyRegion, result);
}

@Test()
public void parseDataResidencyRegionIncorrectJson() {
String invalidJson = "invalidJson";
String result = ErrorLogHelper.parseDataResidencyRegion(invalidJson);
assertNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import androidx.annotation.WorkerThread;

import com.microsoft.appcenter.AbstractAppCenterService;
import com.microsoft.appcenter.AppCenter;
import com.microsoft.appcenter.Constants;
import com.microsoft.appcenter.Flags;
import com.microsoft.appcenter.channel.Channel;
Expand Down Expand Up @@ -639,6 +640,8 @@ private synchronized UUID queueException(@NonNull final ExceptionModelBuilder ex
final String userId = UserIdContext.getInstance().getUserId();
final UUID errorId = UUID.randomUUID();
final Map<String, String> validatedProperties = ErrorLogHelper.validateProperties(properties, "HandledError");
final String dataResidencyRegion = AppCenter.getDataResidencyRegion();

post(new Runnable() {

@Override
Expand All @@ -648,11 +651,17 @@ public void run() {
HandledErrorLog errorLog = new HandledErrorLog();
errorLog.setId(errorId);
errorLog.setUserId(userId);
errorLog.setDataResidencyRegion(dataResidencyRegion);
errorLog.setException(exceptionModelBuilder.buildExceptionModel());
errorLog.setProperties(validatedProperties);
mChannel.enqueue(errorLog, ERROR_GROUP, Flags.DEFAULTS);

/* Then attachments if any. */
if (attachments != null) {
for (ErrorAttachmentLog attachment : attachments) {
attachment.setDataResidencyRegion(dataResidencyRegion);
}
}
sendErrorAttachment(errorId, attachments);
}
});
Expand Down Expand Up @@ -780,6 +789,7 @@ private void processSingleMinidump(File minidumpFile, File minidumpFolder) {
errorLog.setProcessName("");
try {
String savedUserId = ErrorLogHelper.getStoredUserInfo(minidumpFolder);
String dataResidencyRegion = ErrorLogHelper.getStoredDataResidencyRegion(minidumpFolder);
Device savedDeviceInfo = ErrorLogHelper.getStoredDeviceInfo(minidumpFolder);
if (savedDeviceInfo == null) {

Expand All @@ -792,6 +802,7 @@ private void processSingleMinidump(File minidumpFile, File minidumpFolder) {
}
errorLog.setDevice(savedDeviceInfo);
errorLog.setUserId(savedUserId);
errorLog.setDataResidencyRegion(dataResidencyRegion);
saveErrorLogFiles(new NativeException(), errorLog);
if (!minidumpFile.renameTo(dest)) {
throw new IOException("Failed to move file");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.microsoft.appcenter.AppCenter;
import com.microsoft.appcenter.Constants;
import com.microsoft.appcenter.crashes.Crashes;
import com.microsoft.appcenter.crashes.ingestion.models.Exception;
Expand Down Expand Up @@ -144,6 +145,11 @@ public class ErrorLogHelper {
@VisibleForTesting
static String DEVICE_INFO_KEY = "DEVICE_INFO";

/**
* Key for data residency region.
*/
private static final String DATA_RESIDENCY_REGION_KEY = "dataResidencyRegion";

/**
* Key for saving userId to JSON.
*/
Expand All @@ -168,6 +174,9 @@ public static ManagedErrorLog createErrorLog(@NonNull Context context, @NonNull
/* Set user identifier. */
errorLog.setUserId(UserIdContext.getInstance().getUserId());

/* Set data residency region. */
errorLog.setDataResidencyRegion(AppCenter.getDataResidencyRegion());

/* Snapshot device properties. */
try {
errorLog.setDevice(DeviceInfoHelper.getDeviceInfo(context));
Expand Down Expand Up @@ -287,6 +296,7 @@ public static synchronized File getNewMinidumpSubfolderWithContextData(Context c
try {
Device deviceInfo = DeviceInfoHelper.getDeviceInfo(context);
String userIdContext = UserIdContext.getInstance().getUserId();
String dataResidencyRegion = AppCenter.getDataResidencyRegion();
deviceInfo.setWrapperSdkName(WRAPPER_SDK_NAME_NDK);

/* To JSON. */
Expand All @@ -296,6 +306,7 @@ public static synchronized File getNewMinidumpSubfolderWithContextData(Context c
writer.endObject();
String deviceInfoString = writer.toString();
JSONObject jsonObject = new JSONObject();
jsonObject.put(DATA_RESIDENCY_REGION_KEY, dataResidencyRegion);
jsonObject.put(DEVICE_INFO_KEY, deviceInfoString);
jsonObject.put(USER_ID_KEY, userIdContext);

Expand Down Expand Up @@ -371,6 +382,21 @@ public static String getStoredUserInfo(File logFolder) {
return parseUserId(userInformationString);
}

/**
* Get data residency region.
*
* @param logFolder folder where to look for stored data residency region.
* @return a data residency region or null.
*/
@Nullable
public static String getStoredDataResidencyRegion(File logFolder) {
String context = getContextInformation(logFolder);
if (context == null) {
return null;
}
return parseDataResidencyRegion(context);
}

/**
* Get data about userId and deviceInfo in JSON format.
* @param logFolder - path to folder where placed file with data about userId and deviceId.
Expand Down Expand Up @@ -439,6 +465,24 @@ static Device parseDevice(String contextInformation) {
return null;
}

/**
* Look for 'dataResidencyRegion' data in file inside the minidump folder and parse it.
* @param contextInformation - data with information about userId.
* @return dataResidencyRegion or null.
*/
@VisibleForTesting
static String parseDataResidencyRegion(String contextInformation) {
try {
JSONObject jsonObject = new JSONObject(contextInformation);
if (jsonObject.has(DATA_RESIDENCY_REGION_KEY)) {
return jsonObject.getString(DATA_RESIDENCY_REGION_KEY);
}
} catch (JSONException e) {
AppCenterLog.error(Crashes.LOG_TAG, "Failed to deserialize data residency region.", e);
}
return null;
}

/**
* Remove the minidump sub-folders from previous sessions in the 'minidump/new' folder.
* Minidumps from these folders should already be moved to the 'minidump/pending' folder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,26 +428,30 @@ public void getStoredDeviceInfo() throws IOException {
}

@Test
public void getStoredDeviceInfoAndUserIdNull() {
public void getStoredMinidumpFileContentNull() {
File minidumpFolder = mock(File.class);
when(minidumpFolder.listFiles(any(FilenameFilter.class))).thenReturn(null);
Device storedDeviceInfo = ErrorLogHelper.getStoredDeviceInfo(minidumpFolder);
String storedUserId = ErrorLogHelper.getStoredUserInfo(minidumpFolder);
String dataResidencyRegion = ErrorLogHelper.getStoredDataResidencyRegion(minidumpFolder);
assertNull(storedDeviceInfo);
assertNull(storedUserId);
assertNull(dataResidencyRegion);
}

@Test
public void getStoredDeviceInfoAndUserIdEmpty() throws IOException {
public void getStoredMinidumpFileContentEmpty() throws IOException {
File minidumpFolder = mTemporaryFolder.newFolder("minidump");
Device storedDeviceInfo = ErrorLogHelper.getStoredDeviceInfo(minidumpFolder);
String storedUserId = ErrorLogHelper.getStoredUserInfo(minidumpFolder);
String dataResidencyRegion = ErrorLogHelper.getStoredDataResidencyRegion(minidumpFolder);
assertNull(storedDeviceInfo);
assertNull(storedUserId);
assertNull(dataResidencyRegion);
}

@Test
public void getStoredDeviceInfoAndUserInfoCannotRead() throws IOException {
public void getStoredMinidumpFileContentCannotRead() throws IOException {
File minidumpFolder = mTemporaryFolder.newFolder("minidump");
File deviceInfoFile = new File(minidumpFolder, ErrorLogHelper.DEVICE_INFO_FILE);
assertTrue(deviceInfoFile.createNewFile());
Expand All @@ -457,6 +461,8 @@ public void getStoredDeviceInfoAndUserInfoCannotRead() throws IOException {
assertNull(storedDeviceInfo);
String userInfo = ErrorLogHelper.getStoredUserInfo(minidumpFolder);
assertNull(userInfo);
String dataResidencyRegion = ErrorLogHelper.getStoredDataResidencyRegion(minidumpFolder);
assertNull(dataResidencyRegion);
}

@Test
Expand Down
25 changes: 25 additions & 0 deletions sdk/appcenter/src/main/java/com/microsoft/appcenter/AppCenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.os.HandlerThread;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import android.util.Log;
Expand Down Expand Up @@ -236,6 +237,11 @@ public class AppCenter {
*/
private Boolean mAllowedNetworkRequests;

/**
* Country code or any other string to identify residency region..
*/
private @Nullable String mDataResidencyRegion;

/**
* Get unique instance.
*
Expand Down Expand Up @@ -308,6 +314,25 @@ public static void setCountryCode(String countryCode) {
DeviceInfoHelper.setCountryCode(countryCode);
}

/**
* Set the country code or any other string to identify residency region.
*
* @param dataResidencyRegion residency region code.
*/
public static void setDataResidencyRegion(@Nullable String dataResidencyRegion) {
getInstance().mDataResidencyRegion = dataResidencyRegion;
}

/**
* Set the country code or any other string to identify residency region.
*
* @return dataResidencyRegion residency region code if defined.
*/
@Nullable
public static String getDataResidencyRegion() {
return getInstance().mDataResidencyRegion;
}

/**
* Get the current version of App Center SDK.
*
Expand Down
Loading

0 comments on commit 7fffffe

Please sign in to comment.