Skip to content

Commit

Permalink
Merge pull request #80 from DeployGate/jmatsu/feat/allow_opt_out_feat…
Browse files Browse the repository at this point in the history
…ures

Provide opt-out for crash reporting and device capture features
  • Loading branch information
jmatsu authored Mar 15, 2024
2 parents 4bb5b01 + 504541b commit d906650
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 30 deletions.
92 changes: 70 additions & 22 deletions sdk/src/main/java/com/deploygate/sdk/DeployGate.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public void onEvent(
} else if (DeployGateEvent.ACTION_ONESHOT_LOGCAT.equals(action)) {
String captureId = null;

if (mDeployGateClient.isSupported(Compatibility.DEVICE_CAPTURE)) {
if (mHostApp.canUseDeviceCapture() && mDeployGateClient.isSupported(Compatibility.DEVICE_CAPTURE)) {
// still nullable
captureId = extras.getString(DeployGateEvent.EXTRA_CAPTURE_ID);
}
Expand Down Expand Up @@ -266,25 +266,25 @@ public void run() {
*/
private DeployGate(
Context applicationContext,
String author,
DeployGateCallback callback,
CustomLogConfiguration customLogConfiguration,
HostApp hostApp
HostApp hostApp,
DeployGateSdkConfiguration sdkConfiguration
) {
// Don't hold sdkConfiguration to avoid memory leak

mApplicationContext = applicationContext;
mDeployGateClient = new DeployGateClient(applicationContext, DEPLOYGATE_PACKAGE);
mHostApp = hostApp;
mHandler = new Handler();
mLogcatInstructionSerializer = mHostApp.canUseLogcat ? new LogcatInstructionSerializer(mHostApp.packageName) : ILogcatInstructionSerializer.NULL_INSTANCE;
mCustomLogInstructionSerializer = new CustomLogInstructionSerializer(mHostApp.packageName, customLogConfiguration);
mCustomLogInstructionSerializer = new CustomLogInstructionSerializer(mHostApp.packageName, sdkConfiguration.customLogConfiguration);
mCallbacks = new HashSet<>();
mPendingEvents = new HashMap<>();
mExpectedAuthor = author;
mExpectedAuthor = sdkConfiguration.appOwnerName;

prepareBroadcastReceiver();

if (callback != null) {
mCallbacks.add(callback);
if (sdkConfiguration.callback != null) {
mCallbacks.add(sdkConfiguration.callback);
}

mInitializedLatch = new CountDownLatch(1);
Expand Down Expand Up @@ -362,6 +362,7 @@ private void requestServiceInit(final boolean isBoot) {
args.putString(DeployGateEvent.EXTRA_EXPECTED_AUTHOR, mExpectedAuthor);
args.putInt(DeployGateEvent.EXTRA_SDK_VERSION, mHostApp.sdkVersion);
args.putString(DeployGateEvent.EXTRA_SDK_ARTIFACT_VERSION, mHostApp.sdkArtifactVersion);
args.putInt(DeployGateEvent.EXTRA_ACTIVE_FEATURE_FLAGS, mHostApp.activeFeatureFlags);
try {
mRemoteService.init(mRemoteCallback, mHostApp.packageName, args);
} catch (RemoteException e) {
Expand Down Expand Up @@ -424,6 +425,49 @@ static void clear() {
sInstance = null;
}


/**
* Install DeployGate on your application instance. Call this method inside
* of your {@link Application#onCreate()}, in ContentProvider or AndroidX Startup Initializer only once.
*
* @param context Your application's Context. SDK will use {@code context.getApplicationContext} and don't hold this object reference.
* @param sdkConfiguration sdk configuration {@link DeployGateSdkConfiguration}
*
* @throws IllegalStateException
* if this called twice
* @since 4.7.0
*/

public static void install(Context context, DeployGateSdkConfiguration sdkConfiguration) {
if (sInstance != null) {
Log.w(TAG, "DeployGate.install was already called. Ignoring.");
return;
}

Context application = context.getApplicationContext();

HostApp hostApp = new HostApp(
application,
sdkConfiguration
);

if (!hostApp.isSdkEnabled) {
return;
}

if (sdkConfiguration.isCrashReportingEnabled) {
Thread.setDefaultUncaughtExceptionHandler(new DeployGateUncaughtExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
} else {
Logger.d("DeployGateSDK crash reporting hasn't started");
}

sInstance = new DeployGate(
application,
hostApp,
sdkConfiguration
);
}

/**
* Install DeployGate on your application instance. Call this method inside
* of your {@link Application#onCreate()} once.
Expand All @@ -447,6 +491,7 @@ static void clear() {
* @throws IllegalStateException
* if this called twice
* @since r1
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(Application app) {
install(app, (String) null);
Expand All @@ -471,6 +516,7 @@ public static void install(Application app) {
* @throws IllegalStateException
* if this called twice
* @since r2
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand Down Expand Up @@ -505,6 +551,7 @@ public static void install(
* @throws IllegalStateException
* if this called twice
* @since r1
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand Down Expand Up @@ -533,6 +580,7 @@ public static void install(
* @throws IllegalStateException
* if this called twice
* @since r4.2
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand Down Expand Up @@ -563,6 +611,7 @@ public static void install(
* @throws IllegalStateException
* if this called twice
* @since r2
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand Down Expand Up @@ -594,6 +643,7 @@ public static void install(
* @throws IllegalStateException
* if this called twice
* @since r1
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand All @@ -619,6 +669,7 @@ public static void install(
* the release build, set this true.
*
* @since r2
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand Down Expand Up @@ -647,6 +698,7 @@ public static void install(
* set a configuration for custom logging
*
* @since 4.4.0
* @deprecated since 4.7.0. Use {@link DeployGate#install(Context, DeployGateSdkConfiguration)} instead.
*/
public static void install(
Application app,
Expand All @@ -655,19 +707,15 @@ public static void install(
boolean forceApplyOnReleaseBuild,
CustomLogConfiguration customLogConfiguration
) {
if (sInstance != null) {
Log.w(TAG, "DeployGate.install was already called. Ignoring.");
return;
}

HostApp hostApp = new HostApp(app.getApplicationContext());

if (!forceApplyOnReleaseBuild && !hostApp.debuggable) {
return;
}

Thread.setDefaultUncaughtExceptionHandler(new DeployGateUncaughtExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
sInstance = new DeployGate(app.getApplicationContext(), author, callback, customLogConfiguration, hostApp);
install(
app,
new DeployGateSdkConfiguration.Builder()
.setAppOwnerName(author)
.setCustomLogConfiguration(customLogConfiguration)
.setEnabledOnNonDebuggableBuild(forceApplyOnReleaseBuild)
.setCallback(callback)
.build()
);
}

/**
Expand Down
168 changes: 168 additions & 0 deletions sdk/src/main/java/com/deploygate/sdk/DeployGateSdkConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package com.deploygate.sdk;

import com.deploygate.sdk.internal.annotations.Experimental;

public final class DeployGateSdkConfiguration {
final CustomLogConfiguration customLogConfiguration;

final boolean isDisabled;
final boolean isEnabledOnNonDebuggableBuild;

final String appOwnerName;

final boolean isCrashReportingEnabled;


final DeployGateCallback callback;

final boolean isCaptureEnabled;

private DeployGateSdkConfiguration(
Builder builder
) {
this(
builder.isDisabled,
builder.customLogConfiguration,
builder.isEnabledOnNonDebuggableBuild,
builder.appOwnerName,
builder.isCrashReportingEnabled,
builder.isCaptureEnabled,
builder.callback
);
}

private DeployGateSdkConfiguration(
boolean isDisabled,
CustomLogConfiguration customLogConfiguration,
boolean isEnabledOnNonDebuggableBuild,
String appOwnerName,
boolean isCrashReportingEnabled,
boolean isCaptureEnabled,
DeployGateCallback callback
) {
this.customLogConfiguration = customLogConfiguration;
this.isDisabled = isDisabled;
this.isEnabledOnNonDebuggableBuild = isEnabledOnNonDebuggableBuild;
this.appOwnerName = appOwnerName;
this.isCrashReportingEnabled = isCrashReportingEnabled;
this.isCaptureEnabled = isCaptureEnabled;
this.callback = callback;
}

public static final class Builder {
private CustomLogConfiguration customLogConfiguration = new CustomLogConfiguration.Builder().build();

private boolean isDisabled = false;
private boolean isEnabledOnNonDebuggableBuild = false;

private String appOwnerName = null;

private boolean isCrashReportingEnabled = true;

private boolean isCaptureEnabled = true;

private DeployGateCallback callback = null;

public Builder() {
}

/**
* Set a custom log configuration
*
* @param customLogConfiguration
* a configuration object for custom logs like {@link DeployGate#logDebug(String)}
* @see CustomLogConfiguration
* @return self
*/
@Experimental
public Builder setCustomLogConfiguration(CustomLogConfiguration customLogConfiguration) {
this.customLogConfiguration = customLogConfiguration;
return this;
}

/**
* Ensure the authority of this app to prevent casual redistribution via DeployGate.
*
* @param appOwnerName
* A name of this app's owner on DeployGate.
* @return self
*/
public Builder setAppOwnerName(String appOwnerName) {
this.appOwnerName = appOwnerName;
return this;
}

/**
* Disable all SDK features.
*
* @param disabled
* Specify true if you would like to disable SDK completely. Defaults to false.
* @return self
*/
public Builder setDisabled(boolean disabled) {
isDisabled = disabled;
return this;
}

/**
* Enable SDK even on non-debuggable builds.
*
* @param enabledOnNonDebuggableBuild
* Specify true if you would like to enable SDK on non-debuggable builds. Defaults to false.
* @return self
*/
public Builder setEnabledOnNonDebuggableBuild(boolean enabledOnNonDebuggableBuild) {
isEnabledOnNonDebuggableBuild = enabledOnNonDebuggableBuild;
return this;
}

/**
* Enable DeployGate Capture feature.
*
* @param captureEnabled
* Specify true if you would like to use DeployGate Capture feature if available. Otherwise, false. Defaults to true.
* @return self
*/
@Experimental
public Builder setCaptureEnabled(boolean captureEnabled) {
isCaptureEnabled = captureEnabled;
return this;
}

/**
* Enable DeployGate Crash reporting feature.
*
* @param crashReportingEnabled
* Specify true if you would like to use DeployGate Crash reporting feature. Otherwise, false. Defaults to true.
* @return self
*/
public Builder setCrashReportingEnabled(boolean crashReportingEnabled) {
isCrashReportingEnabled = crashReportingEnabled;
return this;
}

/**
* Set a callback of the communication events between DeployGate client app and this app.
*
* @param callback
* Set an instance of callback. The reference won't be released. Please use {@link DeployGate#registerCallback(DeployGateCallback, boolean)} for memory sensitive works.
* @return self
*/
public Builder setCallback(DeployGateCallback callback) {
this.callback = callback;
return this;
}

/**
* @return a new sdk configuration.
*/
public DeployGateSdkConfiguration build() {
if (isDisabled) {
// Create a new builder instance to release all references just in case.
return new DeployGateSdkConfiguration(new Builder().setDisabled(true));
} else {
return new DeployGateSdkConfiguration(this);
}
}
}
}
Loading

0 comments on commit d906650

Please sign in to comment.