-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new callback interfaces split from DeployGateCallback #95
Conversation
…dkConfigration in each module
.setEnabledOnNonDebuggableBuild(true) | ||
.build(); | ||
|
||
DeployGate.install(this, configuration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use install(Context, DeployGateSdkConfiguration)
because install(Application, DeployGateCallback, boolean)
is deprecated.
*/ | ||
public interface DeployGateCallback { | ||
@Deprecated | ||
public interface DeployGateCallback extends DeployGateInitializeCallback, DeployGateStatusChangeCallback, DeployGateUpdateAvailableCallback { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate to DeployGateInitializeCallback, DeployGateStatusChangeCallback, DeployGateUpdateAvailableCallback.
Now, we marked it deprecated.
We can still use this interface, but we plan to delete it in the next major update.
private final HashSet<DeployGateCallback> mCallbacks; | ||
private final HashSet<DeployGateInitializeCallback> mInitializeCallbacks; | ||
private final HashSet<DeployGateStatusChangeCallback> mStatusChangeCallbacks; | ||
private final HashSet<DeployGateUpdateAvailableCallback> mUpdateAvailableCallbacks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose the implementation to keep mCallbacks
to minimize the effect on existing code.
It will be deleted with DeployGateCallback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it means minimizing changes to the current code but not minimizing the effect.
- The current changes mean we are going to keep maintaining two callback mechanisms until we can completely delete the deprecated entities, even tough the new mechanism is compatible with the legacy one.
- The current changes allows at most two callbacks like DeployGateInitializeCallback at the initialization time. It's not a planned feature.
Please remove mCallbacks
property and dispatch the callback registration to each property. It will be completely the same behaviour as the current behaviour i.e. it can minimize the effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I focused on minimizing code changes.
I understood it is important to minimize behavior changes same behavior as the current behavior in this case.
I'll fix it.
// call onInitialized on each callbacks | ||
for (DeployGateCallback callback : mCallbacks) { | ||
callback.onInitialized(true); | ||
} | ||
for (DeployGateInitializeCallback callback : mInitializeCallbacks) { | ||
callback.onInitialized(true); | ||
} | ||
|
||
// after call onInitialized, then call onStatusChanged | ||
for (DeployGateCallback callback : mCallbacks) { | ||
callback.onStatusChanged(isManaged, isAuthorized, loginUsername, isStopped); | ||
} | ||
for (DeployGateStatusChangeCallback callback : mStatusChangeCallbacks) { | ||
callback.onStatusChanged(isManaged, isAuthorized, loginUsername, isStopped); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep order of call callback methods.
We call onInitializad()
first, after that call onStatusCahnged()
.
// call onInitialized on each callbacks | ||
for (DeployGateCallback callback : mCallbacks) { | ||
callback.onInitialized(false); | ||
} | ||
for (DeployGateInitializeCallback callback : mInitializeCallbacks) { | ||
callback.onInitialized(false); | ||
} | ||
|
||
// after call onInitialized, then call onStatusChanged | ||
for (DeployGateCallback callback : mCallbacks) { | ||
callback.onStatusChanged(false, false, null, false); | ||
} | ||
for (DeployGateStatusChangeCallback callback : mStatusChangeCallbacks) { | ||
callback.onStatusChanged(false, false, null, false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added new testcases for DeployGateSdkConfigration.
It checks all public methods are defined each modules(sdk, sdk-mock).
* @deprecated since 4.9.0. Use {@link DeployGateInitializeCallback#onInitialized(boolean)} instead. | ||
*/ | ||
@Deprecated | ||
@Override | ||
public void onInitialized(boolean isServiceAvailable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also delete this method and delegate it to each extended class.
In this case, we cannot mark deprecated to methods in X.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decomposing the current Callback class sounds great.
Please fix unwanted breaking changes when deprecating methods.
@@ -0,0 +1,23 @@ | |||
package com.deploygate.sdk; | |||
|
|||
public interface DeployGateStatusChangeCallback { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add javadocs to new classes.
@@ -62,6 +73,9 @@ public static final class Builder { | |||
private boolean isCaptureEnabled = true; | |||
|
|||
private DeployGateCallback callback = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove here.
*/ | ||
@Deprecated | ||
public Builder setCallback(DeployGateCallback callback) { | ||
this.callback = callback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To keep the current behaviour, at most one callback for each should be allowed.
this.callback = callback; | |
this.initializeCallback = callback; | |
this.statusChangeCallback = callback; | |
this.updateAvailableCallback = callback; |
@@ -12,8 +12,10 @@ public final class DeployGateSdkConfiguration { | |||
|
|||
final boolean isCrashReportingEnabled; | |||
|
|||
|
|||
final DeployGateCallback callback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove here.
*/ | ||
@Deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. Please deprecate these methods in sdk-mock as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't add a comment to registerCallbackInternal
method so let me write it here.
Please fix registerCallbackInternal
to register a DeployGateCallback to each property.
*/ | ||
public static void registerInitializeCallback( | ||
DeployGateInitializeCallback callback, | ||
boolean refreshImmediately |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to provide methods with boolean refreshImmediately
anymore. Alternatively, users should call refresh
manually. It will also be able to avoid leading users to many refresh requests hell.
private final HashSet<DeployGateCallback> mCallbacks; | ||
private final HashSet<DeployGateInitializeCallback> mInitializeCallbacks; | ||
private final HashSet<DeployGateStatusChangeCallback> mStatusChangeCallbacks; | ||
private final HashSet<DeployGateUpdateAvailableCallback> mUpdateAvailableCallbacks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it means minimizing changes to the current code but not minimizing the effect.
- The current changes mean we are going to keep maintaining two callback mechanisms until we can completely delete the deprecated entities, even tough the new mechanism is compatible with the legacy one.
- The current changes allows at most two callbacks like DeployGateInitializeCallback at the initialization time. It's not a planned feature.
Please remove mCallbacks
property and dispatch the callback registration to each property. It will be completely the same behaviour as the current behaviour i.e. it can minimize the effect.
// with setAuthor method when creating DeployGate SdkConfiguration. like: | ||
// | ||
// DeployGate.install(this, "YOURUSERNAME"); | ||
// builder.setAuthor("YOURUSERNAME") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
describe to use setAuthor(String)
method defined in DeployGateSdkConfuration.Builder class because DeployGate.install(Application, String)
is deprecated.
@jmatsu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you wrap a DeployGateCallback by anonymous classes?
@Override | ||
public void onInitialized(boolean isServiceAvailable) { | ||
DeployGateSdkConfiguration configuration = new DeployGateSdkConfiguration.Builder() | ||
// Please note that these callback is called if you have removed the content provider. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iff
is not a typo by the way. It's an abbreviation of if and only if
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh.. reverted this change.
mInitializeCallbacks.add(new DeployGateInitializeCallback() { | ||
@Override | ||
public void onInitialized(boolean isServiceAvailable) { | ||
listener.onInitialized(isServiceAvailable); | ||
} | ||
}); | ||
mStatusChangeCallbacks.add(new DeployGateStatusChangeCallback() { | ||
@Override | ||
public void onStatusChanged(boolean isManaged, boolean isAuthorized, String loginUsername, boolean isStopped) { | ||
listener.onStatusChanged(isManaged, isAuthorized, loginUsername, isStopped); | ||
} | ||
}); | ||
mUpdateAvailableCallbacks.add(new DeployGateUpdateAvailableCallback() { | ||
@Override | ||
public void onUpdateAvailable(int revision, String versionName, int versionCode) { | ||
listener.onUpdateAvailable(revision, versionName, versionCode); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be compilable. What happened?
mInitializeCallbacks.add(new DeployGateInitializeCallback() { | |
@Override | |
public void onInitialized(boolean isServiceAvailable) { | |
listener.onInitialized(isServiceAvailable); | |
} | |
}); | |
mStatusChangeCallbacks.add(new DeployGateStatusChangeCallback() { | |
@Override | |
public void onStatusChanged(boolean isManaged, boolean isAuthorized, String loginUsername, boolean isStopped) { | |
listener.onStatusChanged(isManaged, isAuthorized, loginUsername, isStopped); | |
} | |
}); | |
mUpdateAvailableCallbacks.add(new DeployGateUpdateAvailableCallback() { | |
@Override | |
public void onUpdateAvailable(int revision, String versionName, int versionCode) { | |
listener.onUpdateAvailable(revision, versionName, versionCode); | |
} | |
}); | |
mInitializeCallbacks.add(listener); | |
mStatusChangeCallbacks.add(listener); | |
mUpdateAvailableCallbacks.add(listener); |
The current code breaks unregister methods because their identities have been changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry.
I added new testcases and checked keeping the behavior between before and after.
if (sInstance == null) { | ||
return; | ||
} | ||
if (listener == null) { | ||
return; | ||
} | ||
|
||
sInstance.mCallbacks.remove(listener); | ||
sInstance.mInitializeCallbacks.remove(new DeployGateInitializeCallback() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These codes are completely wrong. Please re-check what this code expects.
By the way, the test job passed so the test codes of unregister
methods are also broken or not tested. Could you please fix them as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No testcase for register/unregister methods exists.
Added it and fixed my code causing unexpected behavior.
/** | ||
* A callback interface to receive DeployGate events. Implement this and pass to | ||
* {@link DeployGate#registerCallback(DeployGateCallback, boolean)} to listen. | ||
* | ||
* @author tnj | ||
* @deprecated since 4.9.0. Use each extended callback interfaces instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @deprecated since 4.9.0. Use each extended callback interfaces instead. | |
* @deprecated since 4.9.0. Use fine-grained callback interfaces for each purpose. |
* A callback interface to receive DeployGate service initialization events.Implement this and pass to | ||
* {@link DeployGate#registerInitializeCallback(DeployGateInitializeCallback)} to listen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be hard to maintain comments if you embedded the detailed usages. see
annotation is enough.
* A callback interface to receive DeployGate service initialization events.Implement this and pass to | |
* {@link DeployGate#registerInitializeCallback(DeployGateInitializeCallback)} to listen. | |
* A callback interface to receive DeployGate service initialization events. |
this.callback = callback; | ||
@Deprecated | ||
public Builder setCallback(final DeployGateCallback callback) { | ||
this.setInitializeCallback(new DeployGateInitializeCallback() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
@jmatsu I added some testcases for check behavior of DeployGate#register, DeployGate#unregister, and DeployGateSdkConfiguration.Builder class. Please re-check this PR. Thanks. |
static HashSet<DeployGateInitializeCallback> getInitializeCallbacks() { | ||
return sInstance != null ? sInstance.mInitializeCallbacks : null; | ||
} | ||
|
||
static HashSet<DeployGateStatusChangeCallback> getStatusChangeCallbacks() { | ||
return sInstance != null ? sInstance.mStatusChangeCallbacks : null; | ||
} | ||
|
||
static HashSet<DeployGateUpdateAvailableCallback> getUpdateAvailableCallbacks() { | ||
return sInstance != null ? sInstance.mUpdateAvailableCallbacks : null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some test cases use these package-private methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost great. Only a few fix is required.
static HashSet<DeployGateInitializeCallback> getInitializeCallbacks() { | ||
return sInstance != null ? sInstance.mInitializeCallbacks : null; | ||
} | ||
|
||
static HashSet<DeployGateStatusChangeCallback> getStatusChangeCallbacks() { | ||
return sInstance != null ? sInstance.mStatusChangeCallbacks : null; | ||
} | ||
|
||
static HashSet<DeployGateUpdateAvailableCallback> getUpdateAvailableCallbacks() { | ||
return sInstance != null ? sInstance.mUpdateAvailableCallbacks : null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static HashSet<DeployGateInitializeCallback> getInitializeCallbacks() { | |
return sInstance != null ? sInstance.mInitializeCallbacks : null; | |
} | |
static HashSet<DeployGateStatusChangeCallback> getStatusChangeCallbacks() { | |
return sInstance != null ? sInstance.mStatusChangeCallbacks : null; | |
} | |
static HashSet<DeployGateUpdateAvailableCallback> getUpdateAvailableCallbacks() { | |
return sInstance != null ? sInstance.mUpdateAvailableCallbacks : null; | |
} | |
/** | |
* Not a public API. This is only for testing. | |
*/ | |
static HashSet<DeployGateInitializeCallback> getInitializeCallbacks() { | |
return sInstance != null ? sInstance.mInitializeCallbacks : null; | |
} | |
/** | |
* Not a public API. This is only for testing. | |
*/ | |
static HashSet<DeployGateStatusChangeCallback> getStatusChangeCallbacks() { | |
return sInstance != null ? sInstance.mStatusChangeCallbacks : null; | |
} | |
/** | |
* Not a public API. This is only for testing. | |
*/ | |
static HashSet<DeployGateUpdateAvailableCallback> getUpdateAvailableCallbacks() { | |
return sInstance != null ? sInstance.mUpdateAvailableCallbacks : null; | |
} |
sdkMock/src/main/java/com/deploygate/sdk/DeployGateSdkConfiguration.java
Show resolved
Hide resolved
import org.junit.runner.RunWith; | ||
|
||
@RunWith(AndroidJUnit4.class) | ||
public class DeployGateTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done!
Thanks! |
We will plan to implement a new callback method for the Capture feature.
Expanding the current callback interface is difficult because we cannot avoid causing breaking changes for many users.
We will maybe have the same problem in the future when planning for new features with callbacks.
So, we separate the DeployGateCallback interface into multiple interfaces.
When new interfaces are added in the future, it will be possible to provide them without affecting users who do not need them.
We take care in making changes to avoid breaking changes.