Skip to content

Commit e7902da

Browse files
Merge branch 'Deep-Link-Routing-Validator-2.0' into Integration-Validator-2.0
# Conflicts: # Branch-SDK/src/main/res/drawable/branch_icon.png
2 parents effe1d5 + 5e1f9f6 commit e7902da

File tree

9 files changed

+689
-3
lines changed

9 files changed

+689
-3
lines changed

Branch-SDK-TestBed/src/main/java/io/branch/branchandroidtestbed/MainActivity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import io.branch.referral.util.LinkProperties;
5656
import io.branch.referral.util.ProductCategory;
5757
import io.branch.referral.util.ShareSheetStyle;
58+
import io.branch.referral.validators.LinkingValidator;
5859

5960
public class MainActivity extends Activity {
6061
private EditText txtShortUrl;
@@ -661,6 +662,7 @@ protected void onStart() {
661662
// IMP : Do not make this call in your production app
662663

663664
//IntegrationValidator.validate(MainActivity.this);
665+
LinkingValidator.validate(MainActivity.this);
664666
}
665667

666668

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.branch.referral.validators;
2+
3+
import android.content.Context;
4+
import android.view.WindowManager;
5+
import android.widget.Button;
6+
7+
import java.util.Objects;
8+
9+
public class LinkingValidator {
10+
private static LinkingValidator instance;
11+
private LinkingValidatorDialog linkingValidatorDialog;
12+
13+
private LinkingValidator(Context context) {}
14+
15+
public static void validate(Context context) {
16+
if (instance == null) {
17+
instance = new LinkingValidator(context);
18+
}
19+
instance.linkingValidatorDialog = new LinkingValidatorDialog(context);
20+
instance.validateDeepLinkRouting(context);
21+
}
22+
23+
private void validateDeepLinkRouting(Context context) {
24+
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
25+
lp.copyFrom(Objects.requireNonNull(instance.linkingValidatorDialog.getWindow()).getAttributes());
26+
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
27+
lp.height = 2000;
28+
instance.linkingValidatorDialog.show();
29+
instance.linkingValidatorDialog.getWindow().setAttributes(lp);
30+
}
31+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.branch.referral.validators;
2+
3+
public class LinkingValidatorConstants {
4+
public static final String canonicalURLPromptText = "Please paste in a web link for the $canonical_url";
5+
public static final String deeplinkPathPromptText = "Please paste in a value for the $deeplink_path";
6+
public static final String customKeyPromptText = "Please enter your custom key and value for routing";
7+
public static final String step1ButtonText = "Next";
8+
public static final String step2ButtonText = " Generate Links for Testing ";
9+
public static final String step3ButtonText = "Done";
10+
public static final String canonicalUrlKey = "$canonical_url";
11+
public static final String deeplinkPathKey = "$deeplink_path";
12+
13+
public static final String linkingValidatorRow1Title = "Link using App Link";
14+
public static final String linkingValidatorRow2Title = "Link using URI scheme";
15+
public static final String linkingValidatorRow3Title = "Web-only link";
16+
public static final String linkingValidatorRow4Title = "Link with missing data";
17+
public static final String linkingValidatorRow5Title = "Warm start use case";
18+
public static final String linkingValidatorRow6Title = "Foreground click use case";
19+
20+
public static final String infoButton1Copy = "Verifies that Universal Links / App Links are working correctly for your Branch domain";
21+
public static final String infoButton2Copy = "Verifies that URI schemes work correctly for your Branch domain";
22+
public static final String infoButton3Copy = "Verifies that web-only links are handled correctly to take you to the mobile web";
23+
public static final String infoButton4Copy = "Verifies that your app gracefully handles Branch links missing deep link data";
24+
public static final String infoButton5Copy = "Click the button to simulate a deep link click for the warm start use case";
25+
public static final String infoButton6Copy = "Click the button to simulate a deep link click for the foreground use case";
26+
27+
public static final String debugButton1Copy = "Ensure you’ve entered the correct SHA 256s on the dashboard and added your Branch domains to the Android Manifest";
28+
public static final String debugButton2Copy = "Ensure that you’ve added a unique Branch URI scheme to the dashboard and Android Manifest";
29+
public static final String debugButton3Copy = "Ensure that your code checks for $web-only in the link data, and if it is true routes the user to the mobile web";
30+
public static final String debugButton4Copy = "Ensure that your code gracefully handles missing or invalid deep link data like taking them to the home screen";
31+
public static final String debugButton5Copy = "Ensure that you are initializing Branch inside of onStart() and that the code is called anytime the app enters the foreground";
32+
public static final String debugButton6Copy = "Ensure that you are calling reInit() inside of onNewIntent() after checking if branch_force_new_session is true";
33+
34+
35+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package io.branch.referral.validators;
2+
3+
import android.app.Dialog;
4+
import android.content.Context;
5+
import android.view.View;
6+
import android.view.Window;
7+
import android.widget.AdapterView;
8+
import android.widget.ArrayAdapter;
9+
import android.widget.Button;
10+
import android.widget.EditText;
11+
import android.widget.LinearLayout;
12+
import android.widget.Spinner;
13+
import android.widget.TextView;
14+
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
18+
import io.branch.referral.R;
19+
20+
public class LinkingValidatorDialog extends Dialog implements AdapterView.OnItemSelectedListener {
21+
22+
private enum ROUTING_TYPE { CANONICAL_URL, DEEPLINK_PATH, CUSTOM }
23+
private ROUTING_TYPE routingType;
24+
private final Button ctaButton;
25+
private final Spinner linkingValidatorDropdownMenu;
26+
private final TextView linkingValidatorText;
27+
private final EditText linkingValidatorEditText;
28+
private final LinearLayout customKVPField;
29+
private final LinearLayout linkingValidatorRowsLayout;
30+
private int step = 1;
31+
private String routingKey = "";
32+
private String routingValue = "";
33+
private LinkingValidatorDialogRowItem row1;
34+
private LinkingValidatorDialogRowItem row2;
35+
private LinkingValidatorDialogRowItem row3;
36+
private LinkingValidatorDialogRowItem row4;
37+
private LinkingValidatorDialogRowItem row5;
38+
private LinkingValidatorDialogRowItem row6;
39+
40+
public LinkingValidatorDialog(final Context context) {
41+
super(context);
42+
requestWindowFeature(Window.FEATURE_NO_TITLE);
43+
this.setContentView(R.layout.dialog_linking_validator);
44+
45+
linkingValidatorDropdownMenu = findViewById(R.id.linkingValidatorDropdownMenu);
46+
List<String> choices = new ArrayList<>();
47+
choices.add(LinkingValidatorConstants.canonicalUrlKey);
48+
choices.add(LinkingValidatorConstants.deeplinkPathKey);
49+
choices.add("other (custom)");
50+
ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, choices);
51+
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
52+
linkingValidatorDropdownMenu.setAdapter(dataAdapter);
53+
linkingValidatorDropdownMenu.setOnItemSelectedListener(this);
54+
55+
ctaButton = findViewById(R.id.linkingValidatorButton);
56+
ctaButton.setText(LinkingValidatorConstants.step1ButtonText);
57+
ctaButton.setOnClickListener(view -> {
58+
switch(step) {
59+
case 1:
60+
LoadStep2Screen();
61+
break;
62+
case 2:
63+
GenerateBranchLinks();
64+
break;
65+
case 3:
66+
CloseDialog();
67+
break;
68+
}
69+
});
70+
71+
linkingValidatorText = findViewById(R.id.linkingValidatorText);
72+
linkingValidatorEditText = findViewById(R.id.linkingValidatorEditText);
73+
customKVPField = findViewById(R.id.customKVPField);
74+
linkingValidatorRowsLayout = findViewById(R.id.linkingValidatorRows);
75+
76+
linkingValidatorEditText.setVisibility(View.GONE);
77+
customKVPField.setVisibility(View.GONE);
78+
linkingValidatorRowsLayout.setVisibility(View.GONE);
79+
80+
routingType = ROUTING_TYPE.CANONICAL_URL;
81+
82+
row1 = findViewById(R.id.linkingValidatorRow1);
83+
row2 = findViewById(R.id.linkingValidatorRow2);
84+
row3 = findViewById(R.id.linkingValidatorRow3);
85+
row4 = findViewById(R.id.linkingValidatorRow4);
86+
row5 = findViewById(R.id.linkingValidatorRow5);
87+
row6 = findViewById(R.id.linkingValidatorRow6);
88+
}
89+
90+
@Override
91+
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
92+
String item = adapterView.getItemAtPosition(i).toString();
93+
switch (item) {
94+
case "$canonical_url":
95+
routingType = ROUTING_TYPE.CANONICAL_URL;
96+
break;
97+
case "$deeplink_path":
98+
routingType = ROUTING_TYPE.DEEPLINK_PATH;
99+
break;
100+
case "other (custom)":
101+
routingType = ROUTING_TYPE.CUSTOM;
102+
break;
103+
}
104+
}
105+
106+
@Override
107+
public void onNothingSelected(AdapterView<?> adapterView) {
108+
109+
}
110+
111+
void LoadStep2Screen() {
112+
step++;
113+
ctaButton.setText(LinkingValidatorConstants.step2ButtonText);
114+
linkingValidatorDropdownMenu.setVisibility(View.GONE);
115+
116+
switch(routingType) {
117+
case CANONICAL_URL:
118+
linkingValidatorEditText.setVisibility(View.VISIBLE);
119+
linkingValidatorText.setText(LinkingValidatorConstants.canonicalURLPromptText);
120+
break;
121+
case DEEPLINK_PATH:
122+
linkingValidatorEditText.setVisibility(View.VISIBLE);
123+
linkingValidatorText.setText(LinkingValidatorConstants.deeplinkPathPromptText);
124+
break;
125+
case CUSTOM:
126+
customKVPField.setVisibility(View.VISIBLE);
127+
linkingValidatorText.setText(LinkingValidatorConstants.customKeyPromptText);
128+
break;
129+
}
130+
}
131+
132+
void GenerateBranchLinks() {
133+
switch(routingType) {
134+
case CANONICAL_URL:
135+
routingKey = LinkingValidatorConstants.canonicalUrlKey;
136+
routingValue = linkingValidatorEditText.getText().toString();
137+
break;
138+
case DEEPLINK_PATH:
139+
routingKey = LinkingValidatorConstants.deeplinkPathKey;
140+
routingValue = linkingValidatorEditText.getText().toString();
141+
break;
142+
}
143+
144+
step++;
145+
linkingValidatorEditText.setVisibility(View.GONE);
146+
customKVPField.setVisibility(View.GONE);
147+
linkingValidatorText.setVisibility(View.GONE);
148+
ctaButton.setText(LinkingValidatorConstants.step3ButtonText);
149+
linkingValidatorRowsLayout.setVisibility(View.VISIBLE);
150+
151+
EditText customKeyEditText = findViewById(R.id.keyEditText);
152+
EditText customValueEditText = findViewById(R.id.valueEditText);
153+
154+
//if routing key is empty, it is a custom key outside of $canonical_url and $deeplink_path
155+
if(routingKey.isEmpty()) {
156+
routingKey = customKeyEditText.getText().toString();
157+
routingValue = customValueEditText.getText().toString();
158+
}
159+
160+
row1.InitializeRow(LinkingValidatorConstants.linkingValidatorRow1Title, LinkingValidatorConstants.infoButton1Copy, LinkingValidatorConstants.debugButton1Copy, routingKey, routingValue, "regularBranchLink", true, 0);
161+
row2.InitializeRow(LinkingValidatorConstants.linkingValidatorRow2Title, LinkingValidatorConstants.infoButton2Copy, LinkingValidatorConstants.debugButton2Copy, routingKey, routingValue, "uriFallbackBranchLink", true, 1, "$uri_redirect_mode", "2");
162+
row3.InitializeRow(LinkingValidatorConstants.linkingValidatorRow3Title, LinkingValidatorConstants.infoButton3Copy, LinkingValidatorConstants.debugButton3Copy, routingKey, routingValue, "webOnlyBranchLink", true, 2, "$web_only", "true");
163+
row4.InitializeRow(LinkingValidatorConstants.linkingValidatorRow4Title, LinkingValidatorConstants.infoButton4Copy, LinkingValidatorConstants.debugButton4Copy, routingKey, "", "missingDataBranchLink", true, 3);
164+
row5.InitializeRow(LinkingValidatorConstants.linkingValidatorRow5Title, LinkingValidatorConstants.infoButton5Copy, LinkingValidatorConstants.debugButton5Copy, routingKey, routingValue, "warmStartUseCase", false, 4);
165+
row6.InitializeRow(LinkingValidatorConstants.linkingValidatorRow6Title, LinkingValidatorConstants.infoButton6Copy, LinkingValidatorConstants.debugButton6Copy, routingKey, routingValue, "foregroundClickUseCase", false, 5);
166+
}
167+
168+
private void CloseDialog() {
169+
this.dismiss();
170+
}
171+
}

0 commit comments

Comments
 (0)