Skip to content

Commit 7c8f58a

Browse files
committed
Allow user to select other apps which should be handled
Signed-off-by: Fung Gwo <fython@163.com>
1 parent f2db71e commit 7c8f58a

22 files changed

+934
-7
lines changed

app/build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ android {
2828
}
2929

3030
dependencies {
31-
final androidxVersion = '1.0.0'
32-
implementation "androidx.core:core:$androidxVersion"
33-
implementation "androidx.annotation:annotation:$androidxVersion"
34-
implementation "androidx.recyclerview:recyclerview:$androidxVersion"
31+
implementation "androidx.core:core:1.0.1"
32+
implementation "androidx.annotation:annotation:1.0.2"
33+
implementation "androidx.recyclerview:recyclerview:1.0.0"
34+
implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
35+
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
3536
}

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
</intent-filter>
3232
</activity>
3333

34+
<activity
35+
android:name=".PackagesSelectorActivity"
36+
android:label="@string/handled_apps_choose_apps"
37+
android:exported="false"/>
3438

3539
<activity
3640
android:name=".ProxyCameraActivity"
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package app.gwo.wechat.docuiproxy;
2+
3+
import android.app.ActionBar;
4+
import android.content.Intent;
5+
import android.content.pm.PackageManager;
6+
import android.os.Bundle;
7+
import android.view.Menu;
8+
import android.view.MenuItem;
9+
import android.view.View;
10+
import android.widget.ProgressBar;
11+
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
15+
import androidx.annotation.NonNull;
16+
import androidx.annotation.Nullable;
17+
import androidx.recyclerview.widget.RecyclerView;
18+
import app.gwo.wechat.docuiproxy.adapter.PackagesSelectorAdapter;
19+
import app.gwo.wechat.docuiproxy.compat.CollectionsCompat;
20+
import app.gwo.wechat.docuiproxy.model.CheckableAppInfo;
21+
import app.gwo.wechat.docuiproxy.util.Settings;
22+
import io.reactivex.Flowable;
23+
import io.reactivex.Single;
24+
import io.reactivex.android.schedulers.AndroidSchedulers;
25+
import io.reactivex.disposables.CompositeDisposable;
26+
import io.reactivex.schedulers.Schedulers;
27+
28+
import static app.gwo.wechat.docuiproxy.Constants.WECHAT_PACKAGE_NAME;
29+
import static java.util.Objects.requireNonNull;
30+
31+
public final class PackagesSelectorActivity extends BaseActivity {
32+
33+
public static final String EXTRA_SELECTED = PackagesSelectorActivity.class.getName() +
34+
".extra.SELECTED";
35+
public static final String EXTRA_PACKAGES_RESULT = PackagesSelectorActivity.class.getName() +
36+
".extra.PACKAGES_RESULT";
37+
38+
public static List<String> getResult(@NonNull Intent intent) {
39+
return intent.getStringArrayListExtra(EXTRA_PACKAGES_RESULT);
40+
}
41+
42+
private RecyclerView mRecyclerView;
43+
private ProgressBar mProgressBar;
44+
45+
private PackagesSelectorAdapter mAdapter = new PackagesSelectorAdapter();
46+
47+
@Nullable
48+
private List<String> mLastSelectedPackages = null;
49+
50+
private final CompositeDisposable mDisposables = new CompositeDisposable();
51+
52+
@Override
53+
protected void onCreate(@Nullable Bundle savedInstanceState) {
54+
super.onCreate(savedInstanceState);
55+
setContentView(R.layout.activity_packages_selector_content);
56+
57+
final Intent intent = getIntent();
58+
if (intent != null) {
59+
mLastSelectedPackages = intent.getStringArrayListExtra(EXTRA_SELECTED);
60+
}
61+
62+
final ActionBar actionBar = requireNonNull(getActionBar());
63+
actionBar.setDisplayHomeAsUpEnabled(true);
64+
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_black_24dp);
65+
66+
mRecyclerView = findViewById(android.R.id.list);
67+
mProgressBar = findViewById(android.R.id.progress);
68+
69+
mAdapter.onRestoreInstanceState(savedInstanceState);
70+
mRecyclerView.setAdapter(mAdapter);
71+
72+
if (savedInstanceState == null) {
73+
loadAppInfoListAsync();
74+
}
75+
}
76+
77+
@Override
78+
protected void onDestroy() {
79+
super.onDestroy();
80+
mDisposables.clear();
81+
}
82+
83+
@Override
84+
protected void onSaveInstanceState(Bundle outState) {
85+
super.onSaveInstanceState(outState);
86+
mAdapter.onSaveInstanceState(outState);
87+
}
88+
89+
@Override
90+
public boolean onCreateOptionsMenu(Menu menu) {
91+
getMenuInflater().inflate(R.menu.menu_packages_selector, menu);
92+
return true;
93+
}
94+
95+
@Override
96+
public boolean onOptionsItemSelected(MenuItem item) {
97+
if (R.id.action_done == item.getItemId()) {
98+
done();
99+
return true;
100+
}
101+
return super.onOptionsItemSelected(item);
102+
}
103+
104+
private void loadAppInfoListAsync() {
105+
mProgressBar.setVisibility(View.VISIBLE);
106+
mDisposables.clear();
107+
mDisposables.add(Single.fromCallable(this::loadAppInfoList)
108+
.toFlowable()
109+
.flatMap(Flowable::fromIterable)
110+
.sorted()
111+
.toList()
112+
.subscribeOn(Schedulers.io())
113+
.observeOn(AndroidSchedulers.mainThread())
114+
.subscribe((res, err) -> {
115+
mProgressBar.setVisibility(View.GONE);
116+
if (err != null) {
117+
err.printStackTrace();
118+
return;
119+
}
120+
mAdapter.updateData(res);
121+
if (mLastSelectedPackages != null) {
122+
final List<String> packages = new ArrayList<>(mLastSelectedPackages);
123+
if (!packages.contains(WECHAT_PACKAGE_NAME)) {
124+
packages.add(WECHAT_PACKAGE_NAME);
125+
}
126+
mAdapter.updateCheckedPackages(packages);
127+
}
128+
})
129+
);
130+
}
131+
132+
private List<CheckableAppInfo> loadAppInfoList() {
133+
final PackageManager pm = getPackageManager();
134+
final List<String> checkedPacks = Settings.getInstance().getHandledApps();
135+
return CollectionsCompat.mapToList(pm.getInstalledApplications(0), item -> {
136+
final CheckableAppInfo cai = CheckableAppInfo.build(this, item);
137+
if (WECHAT_PACKAGE_NAME.equals(cai.getPackageName())) {
138+
cai.setChecked(true);
139+
cai.setCheckable(false);
140+
} else {
141+
cai.setChecked(CollectionsCompat.anyMatch(
142+
checkedPacks, pack -> pack.equals(cai.getPackageName())));
143+
}
144+
return cai;
145+
});
146+
}
147+
148+
private void done() {
149+
Intent resultIntent = new Intent();
150+
resultIntent.putStringArrayListExtra(EXTRA_PACKAGES_RESULT,
151+
Flowable.fromIterable(mAdapter.getCheckedData())
152+
.filter(item -> !WECHAT_PACKAGE_NAME.equals(item.getPackageName()))
153+
.map(CheckableAppInfo::getPackageName)
154+
.toList()
155+
.map(ArrayList::new)
156+
.blockingGet()
157+
);
158+
setResult(RESULT_OK, resultIntent);
159+
finish();
160+
}
161+
162+
}

app/src/main/java/app/gwo/wechat/docuiproxy/ProxyCameraActivity.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public final class ProxyCameraActivity extends BaseActivity {
2828
public static final int REQUEST_CODE_OPEN = 1;
2929
public static final int REQUEST_CODE_CAPTURE = 2;
3030

31-
private boolean isFromWeChat = false;
31+
private boolean shouldBeHandled = false;
3232

3333
private Uri mExpectedOutput = null;
3434

@@ -55,8 +55,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5555
getExtrasFromCaptureIntent(intent);
5656

5757
// Start process
58-
isFromWeChat = Constants.WECHAT_PACKAGE_NAME.equals(getReferrerPackage());
59-
if (isFromWeChat) {
58+
shouldBeHandled = Settings.isSourceAppShouldBeHandled(getReferrerPackage());
59+
if (shouldBeHandled) {
6060
Log.d(TAG, "Receive an valid capture intent from WeChat. " +
6161
"Now we start process it.");
6262
processIntentForWeChat(intent);

app/src/main/java/app/gwo/wechat/docuiproxy/SettingsActivity.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,37 @@
11
package app.gwo.wechat.docuiproxy;
22

3+
import android.Manifest;
4+
import android.content.Intent;
5+
import android.content.pm.PackageManager;
6+
import android.os.Build;
37
import android.os.Bundle;
8+
import android.preference.Preference;
49
import android.preference.PreferenceFragment;
510
import android.widget.Toast;
611

12+
import java.util.List;
13+
714
import androidx.annotation.Nullable;
815
import app.gwo.wechat.docuiproxy.util.Settings;
916

1017
public final class SettingsActivity extends BaseActivity {
1118

19+
private static final int REQUEST_CODE_PACKAGES_SELECTOR = 10;
20+
1221
@Override
1322
protected void onCreate(@Nullable Bundle savedInstanceState) {
1423
super.onCreate(savedInstanceState);
1524

25+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
26+
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
27+
!= PackageManager.PERMISSION_GRANTED) {
28+
requestPermissions(new String[] {
29+
Manifest.permission.READ_EXTERNAL_STORAGE,
30+
Manifest.permission.WRITE_EXTERNAL_STORAGE
31+
}, 0);
32+
}
33+
}
34+
1635
if (savedInstanceState == null) {
1736
getFragmentManager()
1837
.beginTransaction()
@@ -24,6 +43,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
2443
public static final class SettingsFragment extends PreferenceFragment {
2544

2645
private static final String KEY_PREFERRED_CAMERA_CLEAR = "clear_preferred_camera";
46+
private static final String KEY_HANDLED_APPS_CHOOSE = "handled_apps_choose";
47+
48+
private Preference mHandledAppsChoose;
2749

2850
@Override
2951
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -35,6 +57,36 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
3557
Toast.makeText(getActivity(), R.string.toast_cleared, Toast.LENGTH_LONG).show();
3658
return true;
3759
});
60+
61+
mHandledAppsChoose = findPreference(KEY_HANDLED_APPS_CHOOSE);
62+
mHandledAppsChoose.setOnPreferenceClickListener(p -> {
63+
startActivityForResult(
64+
new Intent(getActivity(), PackagesSelectorActivity.class),
65+
REQUEST_CODE_PACKAGES_SELECTOR
66+
);
67+
return true;
68+
});
69+
updateHandledAppsSummary();
70+
}
71+
72+
@Override
73+
public void onActivityResult(int requestCode, int resultCode, Intent data) {
74+
if (REQUEST_CODE_PACKAGES_SELECTOR == requestCode
75+
&& RESULT_OK == resultCode
76+
&& data != null) {
77+
final List<String> result = PackagesSelectorActivity.getResult(data);
78+
Settings.getInstance().setHandledApps(result);
79+
updateHandledAppsSummary(result.size());
80+
}
81+
}
82+
83+
private void updateHandledAppsSummary() {
84+
updateHandledAppsSummary(Settings.getInstance().getHandledApps().size());
85+
}
86+
87+
private void updateHandledAppsSummary(int count) {
88+
mHandledAppsChoose.setSummary(getString(
89+
R.string.handled_apps_choose_apps_summary, count));
3890
}
3991

4092
}

0 commit comments

Comments
 (0)