Skip to content

Commit

Permalink
Merge pull request #1276 from microsoft/develop
Browse files Browse the repository at this point in the history
Version 2.4.0
  • Loading branch information
zhangcc01 authored Oct 14, 2019
2 parents fd394bb + 15762ac commit 7751a1f
Show file tree
Hide file tree
Showing 94 changed files with 5,692 additions and 3,191 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# App Center SDK for Android Change Log

## Version 2.4.0

### App Center Crashes

* **[Behavior change]** Deprecate and remove insecure implementation of `ErrorReport.getThrowable()`, which now always returns `null`. Use the new `ErrorReport.getStackTrace()` as an alternative.

### App Center Data

* **[Fix]** Reduced retries on Data-related operations to fail fast and avoid the perception of calls "hanging".

### App Center Distribute

* **[Fix]** Downloading in-app update APK file has been failing on Android 4.x since TLS 1.2 has been enforced early September. The file is now downloaded using HTTPS direct connection when running on Android 4 instead of relying on system's download manager.
* **[Breaking change]** If your `minSdkVersion` is lower than `19`, Android requires the `WRITE_EXTERNAL_STORAGE` permission to store new downloaded updates. Please refer to the updated documentation site for detailed instructions. This is related to the download fix.

___

## Version 2.3.0

### App Center Auth
Expand Down
21 changes: 21 additions & 0 deletions apps/sasquatch/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,24 @@
-keepclasseswithmembers class com.microsoft.appcenter.ingestion.models.Device {
public ** get*();
}
-keepclasseswithmembers class com.microsoft.appcenter.analytics.EventProperties {
** getProperties();
}
-keepclasseswithmembers class com.microsoft.appcenter.analytics.PropertyConfigurator {
private ** get*();
private ** mEventProperties;
}
-keepclasseswithmembers class * extends com.microsoft.appcenter.ingestion.models.properties.TypedProperty {
** getValue();
}

# For some reason the previous rule doesn't work with primitive getValue return type
-keepclasseswithmembers class com.microsoft.appcenter.ingestion.models.properties.BooleanTypedProperty {
public boolean getValue();
}
-keepclasseswithmembers class com.microsoft.appcenter.ingestion.models.properties.LongTypedProperty {
public long getValue();
}
-keepclasseswithmembers class com.microsoft.appcenter.ingestion.models.properties.DoubleTypedProperty {
public double getValue();
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withChild;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.util.Log.getStackTraceString;
import static com.microsoft.appcenter.sasquatch.activities.utils.EspressoUtils.CHECK_DELAY;
import static com.microsoft.appcenter.sasquatch.activities.utils.EspressoUtils.TOAST_DELAY;
import static com.microsoft.appcenter.sasquatch.activities.utils.EspressoUtils.onToast;
Expand All @@ -57,7 +58,6 @@
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
Expand Down Expand Up @@ -184,9 +184,7 @@ private void crashTest(@StringRes int titleId) throws InterruptedException {
new Date().getTime() - errorReport.getAppErrorTime().getTime(),
lessThan(10000L));
assertNotNull(errorReport.getDevice());
assertEquals(failureHandler.uncaughtException.getClass(), errorReport.getThrowable().getClass());
assertEquals(failureHandler.uncaughtException.getMessage(), errorReport.getThrowable().getMessage());
assertArrayEquals(failureHandler.uncaughtException.getStackTrace(), errorReport.getThrowable().getStackTrace());
assertEquals(getStackTraceString(failureHandler.uncaughtException), errorReport.getStackTrace());

/* Send report. */
waitFor(onView(withText(R.string.crash_confirmation_dialog_send_button))
Expand Down
14 changes: 14 additions & 0 deletions apps/sasquatch/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.microsoft.appcenter.sasquatch">

<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />

<application
android:name=".SasquatchApplication"
android:allowBackup="false"
Expand Down Expand Up @@ -85,6 +89,16 @@
android:host="auth"
android:scheme="@string/msal_redirect_scheme" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="auth"
android:scheme="@string/msal_redirect_scheme_aad" />
</intent-filter>
</activity>

<!-- Set default notification icon and color. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public void onClick(View v) {
startMSALoginActivity(AuthenticationProvider.Type.MSA_DELEGATE);
}
}));
mFeatureList.add(new TestFeatures.TestFeature(R.string.b2c_sign_in_title, R.string.b2c_sign_in_description, new View.OnClickListener() {
mFeatureList.add(new TestFeatures.TestFeatureTitle(R.string.auth_title));
mFeatureList.add(new TestFeatures.TestFeature(R.string.sign_in_title, R.string.sign_in_description, new View.OnClickListener() {

@Override
public void onClick(View v) {
Expand Down Expand Up @@ -97,7 +98,7 @@ public void accept(SignInResult signInResult) {
});
}
}));
mFeatureList.add(new TestFeatures.TestFeature(R.string.b2c_sign_out_title, R.string.b2c_sign_out_description, new View.OnClickListener() {
mFeatureList.add(new TestFeatures.TestFeature(R.string.sign_out_title, R.string.sign_out_description, new View.OnClickListener() {

@Override
public void onClick(View v) {
Expand Down Expand Up @@ -138,28 +139,28 @@ private void loadAuthStatus(boolean loadDefaultStatus) {
}

private TestFeatures.TestFeature getAuthenticationDefaultTestFeature() {
return getAuthenticationTestFeature(R.string.b2c_authentication_status_description);
return getAuthenticationTestFeature(R.string.authentication_status_description);
}

private TestFeatures.TestFeature getAuthenticatedTestFeature() {
return getAuthenticationTestFeature(R.string.b2c_authentication_status_authenticated);
return getAuthenticationTestFeature(R.string.authentication_status_authenticated);
}

private TestFeatures.TestFeature getNotAuthenticatedTestFeature() {
return getAuthenticationTestFeature(R.string.b2c_authentication_status_not_authenticated);
return getAuthenticationTestFeature(R.string.authentication_status_not_authenticated);
}

private TestFeatures.TestFeature getAuthenticationTestFeature(int valueStringId) {
return new TestFeatures.TestFeature(R.string.b2c_authentication_status_title, valueStringId, new View.OnClickListener() {
return new TestFeatures.TestFeature(R.string.authentication_status_title, valueStringId, new View.OnClickListener() {

@Override
public void onClick(View v) {
if (isAuthenticated()) {
startUserInfoActivity(sUserInformation);
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(AuthenticationProviderActivity.this);
builder.setTitle(R.string.b2c_authentication_status_dialog_unavailable_title)
.setMessage(R.string.b2c_authentication_status_dialog_unavailable_description)
builder.setTitle(R.string.authentication_status_dialog_unavailable_title)
.setMessage(R.string.authentication_status_dialog_unavailable_description)
.setPositiveButton(R.string.alert_ok, new DialogInterface.OnClickListener() {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void onClick(View v) {
return true;
}

@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "ConstantConditions"})
private void updatePropertyList() {
try {
Field field = getSelectedTarget().getPropertyConfigurator().getClass().getDeclaredField("mEventProperties");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.StrictMode;
Expand Down Expand Up @@ -121,6 +122,7 @@ static String getLogUrl(Context context, String startType) {
switch (StartType.valueOf(startType)) {
case TARGET:
case NO_SECRET:
case SKIP_START:
return context.getString(R.string.log_url_one_collector);
}
return context.getString(R.string.log_url);
Expand All @@ -145,7 +147,7 @@ static void startAppCenter(Application application, String startTypeString) {
if (startType == StartType.SKIP_START) {
return;
}
String appId = sSharedPreferences.getString(APP_SECRET_KEY, application.getString(R.string.app_secret));
String appId = sSharedPreferences.getString(APP_SECRET_KEY, getDefaultAppSecret(application.getResources()));
String targetId = sSharedPreferences.getString(TARGET_KEY, application.getString(R.string.target_id));
String appIdArg = "";
switch (startType) {
Expand Down Expand Up @@ -371,7 +373,14 @@ public void accept(Boolean crashed) {
@Override
public void accept(ErrorReport data) {
if (data != null) {
Log.i(LOG_TAG, "Crashes.getLastSessionCrashReport().getThrowable()=", data.getThrowable());

/* TODO uncomment the next line, remove reflection and catch block after API available to jCenter. */
/* Log.i(LOG_TAG, "Crashes.getLastSessionCrashReport().getStackTrace()=" + data.getStackTrace()); */
try {
String stackTrace = (String) ErrorReport.class.getMethod("getStackTrace").invoke(data);
Log.i(LOG_TAG, "Crashes.getLastSessionCrashReport().getStackTrace()=" + stackTrace);
} catch (Exception ignored) {
}
}
}
});
Expand All @@ -384,6 +393,17 @@ public void accept(ErrorReport data) {
listView.setOnItemClickListener(TestFeatures.getOnItemClickListener());
}

/* Get the default app secret from the app secret array. */
static String getDefaultAppSecret(Resources resources) {
final String[] secretValuesArray = resources.getStringArray(R.array.appcenter_secrets);
return secretValuesArray[0];
}

static String getCustomAppSecretString(Resources resources) {
final String[] secretValuesArray = resources.getStringArray(R.array.appcenter_secrets);
return secretValuesArray[secretValuesArray.length - 1];
}

private void setDistributeEnabledForDebuggableBuild() {
boolean enabledForDebuggableBuild = sSharedPreferences.getBoolean(getString(R.string.appcenter_distribute_debug_state_key), false);
Distribute.setEnabledForDebuggableBuild(enabledForDebuggableBuild);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,23 +494,49 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}
});
initEditText(R.string.app_secret_key, R.string.app_secret_title, APP_SECRET_KEY, getString(R.string.app_secret), new EditTextListener() {
final String defaultAppSecret = MainActivity.getDefaultAppSecret(getActivity().getResources());
final String appSecret = MainActivity.sSharedPreferences.getString(APP_SECRET_KEY, defaultAppSecret);
initChangeableSetting(R.string.app_secret_key, appSecret, new Preference.OnPreferenceChangeListener() {

@Override
public void onSave(String value) {
public boolean onPreferenceChange(final Preference preference, Object newValue) {
if (newValue == null) {
return true;
}
String value = newValue.toString();

if (!TextUtils.isEmpty(value)) {
setKeyValue(APP_SECRET_KEY, value);
Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.app_secret_changed_format), value), Toast.LENGTH_SHORT).show();
if (value.equals(MainActivity.getCustomAppSecretString(getActivity().getResources()))) {

/* If user selected custom, popup a text editor so they can enter whatever they want. */
showPreferenceTextEditor(getPreferenceManager().findPreference(getString(R.string.app_secret_key)), R.string.app_secret_title, APP_SECRET_KEY, defaultAppSecret, new EditTextListener() {

@Override
public void onSave(String value) {
if (!TextUtils.isEmpty(value)) {
setKeyValue(APP_SECRET_KEY, value);
Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.app_secret_changed_format), value), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), R.string.app_secret_invalid, Toast.LENGTH_SHORT).show();
}
}

@Override
public void onReset() {
setKeyValue(APP_SECRET_KEY, defaultAppSecret);
preference.setSummary(MainActivity.sSharedPreferences.getString(APP_SECRET_KEY, null));
Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.app_secret_changed_format), defaultAppSecret), Toast.LENGTH_SHORT).show();
}
});
} else {
setKeyValue(APP_SECRET_KEY, value);
preference.setSummary(MainActivity.sSharedPreferences.getString(APP_SECRET_KEY, null));
Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.app_secret_changed_format), value), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), R.string.app_secret_invalid, Toast.LENGTH_SHORT).show();
}
}

@Override
public void onReset() {
String defaultAppSecret = getString(R.string.app_secret);
setKeyValue(APP_SECRET_KEY, defaultAppSecret);
Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.app_secret_changed_format), defaultAppSecret), Toast.LENGTH_SHORT).show();
return true;
}
});

Expand Down Expand Up @@ -740,32 +766,37 @@ private void initEditText(int key, final int title, final String preferencesKey,

@Override
public boolean onPreferenceClick(final Preference preference) {
final EditText input = new EditText(getActivity());
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(MainActivity.sSharedPreferences.getString(preferencesKey, defaultValue));

new AlertDialog.Builder(getActivity()).setTitle(title).setView(input)
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onSave(input.getText().toString());
preference.setSummary(getSummary(preferencesKey, defaultValue));
}
})
.setNeutralButton(R.string.reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onReset();
preference.setSummary(getSummary(preferencesKey, defaultValue));
}
})
.setNegativeButton(R.string.cancel, null)
.create().show();
return true;
return showPreferenceTextEditor(preference, title, preferencesKey, defaultValue, listener);
}
});
}

private boolean showPreferenceTextEditor(final Preference preference, final int title, final String preferencesKey, final String defaultValue, final EditTextListener listener) {
final EditText input = new EditText(getActivity());
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(MainActivity.sSharedPreferences.getString(preferencesKey, defaultValue));

/* Actually show the text entry dialog. */
new AlertDialog.Builder(getActivity()).setTitle(title).setView(input)
.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onSave(input.getText().toString());
preference.setSummary(getSummary(preferencesKey, defaultValue));
}
})
.setNeutralButton(R.string.reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onReset();
preference.setSummary(getSummary(preferencesKey, defaultValue));
}
})
.setNegativeButton(R.string.cancel, null)
.create().show();
return true;
}

private void initCheckBoxSetting(int key, final int enabledSummary, final int disabledSummary, final HasEnabled hasEnabled) {
Preference preference = getPreferenceManager().findPreference(getString(key));
if (preference == null) {
Expand Down
Loading

0 comments on commit 7751a1f

Please sign in to comment.