Skip to content

Commit f970bc9

Browse files
committed
feat: Added (again) self-check option in settings to see and configure app permissions
Patched apps checks: Check currently installed apps that are running with microG. Also detect whether apps use Morphe patches based on package name detection. Permissions checks: Verify whether essential microG special permissions are granted. System checks: Verify that the system is correctly configured to run microG, specifically background services.
1 parent bcf8337 commit f970bc9

File tree

17 files changed

+482
-160
lines changed

17 files changed

+482
-160
lines changed

play-services-core/microg-ui-tools/src/main/java/org/microg/tools/selfcheck/SelfCheckGroup.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@
1717
package org.microg.tools.selfcheck;
1818

1919
import android.content.Context;
20-
2120
import androidx.fragment.app.Fragment;
21+
import org.microg.tools.ui.AbstractSelfCheckFragment.ChipInfo;
22+
import java.util.List;
2223

2324
public interface SelfCheckGroup {
2425
String getGroupName(Context context);
2526

2627
void doChecks(Context context, ResultCollector collector);
2728

2829
interface ResultCollector {
29-
void addResult(String name, Result value, String resolution);
30-
31-
void addResult(String name, Result value, String resolution, CheckResolver resolver);
30+
void addResult(String name, Result result, String resolution);
31+
void addResult(String name, Result result, String resolution, CheckResolver resolver);
32+
void addResult(String name, Result result, String resolution, boolean showIcon, List<ChipInfo> chips, CheckResolver resolver);
3233
}
3334

3435
interface CheckResolver {

play-services-core/microg-ui-tools/src/main/java/org/microg/tools/ui/AbstractSelfCheckFragment.java

Lines changed: 101 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,61 +16,89 @@
1616

1717
package org.microg.tools.ui;
1818

19+
import android.content.Intent;
20+
import android.graphics.drawable.Drawable;
1921
import android.os.Bundle;
20-
import android.view.MotionEvent;
21-
import android.util.Log;
22+
import android.text.Html;
2223
import android.view.LayoutInflater;
2324
import android.view.View;
2425
import android.view.ViewGroup;
25-
import android.widget.CheckBox;
26+
import android.widget.ImageView;
2627
import android.widget.TextView;
2728

29+
import androidx.activity.result.ActivityResultLauncher;
30+
import androidx.activity.result.contract.ActivityResultContracts;
2831
import androidx.annotation.Nullable;
2932
import androidx.fragment.app.Fragment;
3033

34+
import com.google.android.material.chip.Chip;
35+
import com.google.android.material.chip.ChipGroup;
36+
import com.google.android.material.transition.platform.MaterialSharedAxis;
37+
3138
import org.microg.tools.selfcheck.SelfCheckGroup;
3239

3340
import java.util.ArrayList;
3441
import java.util.List;
3542

3643
import static android.view.View.GONE;
44+
import static android.view.View.VISIBLE;
3745
import static android.view.View.INVISIBLE;
3846
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
3947
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
4048
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;
4149

4250
public abstract class AbstractSelfCheckFragment extends Fragment {
43-
private static final String TAG = "SelfCheck";
44-
4551
private ViewGroup root;
52+
protected ActivityResultLauncher<Intent> resolutionLauncher;
53+
protected ActivityResultLauncher<String[]> permissionsLauncher;
54+
55+
public static class ChipInfo {
56+
public String label;
57+
public Drawable icon;
58+
public View.OnClickListener onClick;
59+
60+
public ChipInfo(String label, Drawable icon, View.OnClickListener onClick) {
61+
this.label = label;
62+
this.icon = icon;
63+
this.onClick = onClick;
64+
}
65+
}
66+
67+
@Override
68+
public void onCreate(Bundle savedInstanceState) {
69+
super.onCreate(savedInstanceState);
70+
resolutionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), r -> reset(LayoutInflater.from(getContext())));
71+
permissionsLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), r -> reset(LayoutInflater.from(getContext())));
72+
73+
setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.X, true));
74+
setExitTransition(new MaterialSharedAxis(MaterialSharedAxis.X, true));
75+
}
76+
77+
public void launchIntent(Intent intent) {
78+
resolutionLauncher.launch(intent);
79+
}
4680

4781
@Nullable
4882
@Override
4983
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
50-
View scrollRoot = inflater.inflate(R.layout.self_check, container, false);
51-
root = scrollRoot.findViewById(R.id.self_check_root);
84+
View scrollRoot = inflater.inflate(org.microg.tools.ui.R.layout.self_check, container, false);
85+
root = scrollRoot.findViewById(org.microg.tools.ui.R.id.self_check_root);
5286
reset(inflater);
5387
return scrollRoot;
5488
}
5589

5690
protected abstract void prepareSelfCheckList(List<SelfCheckGroup> checks);
5791

5892
protected void reset(LayoutInflater inflater) {
93+
if (root == null) return;
5994
List<SelfCheckGroup> selfCheckGroupList = new ArrayList<>();
6095
prepareSelfCheckList(selfCheckGroupList);
61-
6296
root.removeAllViews();
6397
for (SelfCheckGroup group : selfCheckGroupList) {
64-
View groupView = inflater.inflate(R.layout.self_check_group, root, false);
98+
View groupView = inflater.inflate(org.microg.tools.ui.R.layout.self_check_group, root, false);
6599
((TextView) groupView.findViewById(android.R.id.title)).setText(group.getGroupName(getContext()));
66-
final ViewGroup viewGroup = groupView.findViewById(R.id.group_content);
67-
final SelfCheckGroup.ResultCollector collector = new GroupResultCollector(viewGroup);
68-
try {
69-
group.doChecks(getContext(), collector);
70-
} catch (Exception e) {
71-
Log.w(TAG, "Failed during check " + group.getGroupName(getContext()), e);
72-
collector.addResult("Self-check failed:", Negative, "An exception occurred during self-check. Please report this issue.");
73-
}
100+
final ViewGroup viewGroup = groupView.findViewById(org.microg.tools.ui.R.id.group_content);
101+
group.doChecks(getContext(), new GroupResultCollector(viewGroup));
74102
root.addView(groupView);
75103
}
76104
}
@@ -83,56 +111,80 @@ public GroupResultCollector(ViewGroup viewGroup) {
83111
}
84112

85113
@Override
86-
public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution) {
87-
addResult(name, result, resolution, null);
114+
public void addResult(String name, SelfCheckGroup.Result result, String resolution) {
115+
addResult(name, result, resolution, true, null, null);
88116
}
89117

90118
@Override
91-
public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution, final SelfCheckGroup.CheckResolver resolver) {
92-
if (result == null || getActivity() == null) return;
93-
getActivity().runOnUiThread(() -> {
94-
View resultEntry = LayoutInflater.from(getContext()).inflate(R.layout.self_check_entry, viewGroup, false);
119+
public void addResult(String name, SelfCheckGroup.Result result, String resolution, SelfCheckGroup.CheckResolver resolver) {
120+
addResult(name, result, resolution, true, null, resolver);
121+
}
95122

96-
TextView nameView = resultEntry.findViewById(R.id.self_check_name);
97-
TextView resolutionView = resultEntry.findViewById(R.id.self_check_resolution);
98-
CheckBox checkBox = resultEntry.findViewById(R.id.self_check_result);
99-
resultEntry.findViewById(R.id.list_item_check);
123+
@Override
124+
public void addResult(String name, SelfCheckGroup.Result result, String resolution, boolean showIcon, List<ChipInfo> chips, SelfCheckGroup.CheckResolver resolver) {
125+
if (getActivity() == null || getContext() == null) return;
126+
getActivity().runOnUiThread(() -> {
127+
View entry = LayoutInflater.from(getContext()).inflate(org.microg.tools.ui.R.layout.self_check_entry, viewGroup, false);
128+
TextView nameView = entry.findViewById(org.microg.tools.ui.R.id.self_check_name);
129+
TextView resView = entry.findViewById(org.microg.tools.ui.R.id.self_check_resolution);
130+
ImageView resultIcon = entry.findViewById(org.microg.tools.ui.R.id.self_check_result_icon);
131+
ChipGroup chipGroup = entry.findViewById(org.microg.tools.ui.R.id.self_check_chip_group);
100132

101133
nameView.setText(name);
102134

103-
resultEntry.findViewById(R.id.self_check_result).setOnTouchListener((v, event) -> {
104-
if (event.getAction() == MotionEvent.ACTION_UP) {
105-
if (event.getX() >= 0 && event.getX() <= v.getWidth() && event.getY() >= 0 && event.getY() <= v.getHeight()) {
106-
v.performClick();
107-
}
135+
if (showIcon) {
136+
resultIcon.setVisibility(VISIBLE);
137+
if (result == Positive) {
138+
resultIcon.setActivated(true);
139+
} else if (result == Negative) {
140+
resultIcon.setActivated(false);
141+
} else {
142+
resultIcon.setVisibility(INVISIBLE);
108143
}
109-
return true;
110-
});
144+
} else {
145+
resultIcon.setVisibility(GONE);
146+
}
111147

112148
if (result == Positive) {
113-
checkBox.setChecked(true);
114-
resolutionView.setVisibility(GONE);
149+
resView.setVisibility(GONE);
115150
} else {
116-
resolutionView.setText(resolution);
117-
if (result == Unknown) {
118-
checkBox.setVisibility(INVISIBLE);
119-
}
151+
resView.setVisibility(VISIBLE);
152+
resView.setText(Html.fromHtml(resolution, Html.FROM_HTML_MODE_COMPACT));
120153
if (resolver != null) {
121-
resultEntry.setClickable(true);
122-
resultEntry.setOnClickListener(v -> resolver.tryResolve(AbstractSelfCheckFragment.this));
154+
entry.setClickable(true);
155+
entry.setOnClickListener(v -> resolver.tryResolve(AbstractSelfCheckFragment.this));
123156
}
124157
}
125158

126-
viewGroup.addView(resultEntry);
127-
128-
for (int i = 0; i < viewGroup.getChildCount(); i++) {
129-
View child = viewGroup.getChildAt(i);
130-
com.google.android.material.listitem.ListItemLayout layout = child.findViewById(R.id.list_item_check);
131-
if (layout != null) {
132-
layout.updateAppearance(i, viewGroup.getChildCount());
159+
if (chips != null && !chips.isEmpty()) {
160+
chipGroup.setVisibility(VISIBLE);
161+
chipGroup.removeAllViews();
162+
for (ChipInfo info : chips) {
163+
Chip chip = (Chip) LayoutInflater.from(getContext()).inflate(org.microg.tools.ui.R.layout.self_check_chip, chipGroup, false);
164+
chip.setText(info.label);
165+
if (info.icon != null) {
166+
chip.setChipIcon(info.icon);
167+
chip.setChipIconVisible(true);
168+
}
169+
if (info.onClick != null) {
170+
chip.setOnClickListener(info.onClick);
171+
}
172+
chipGroup.addView(chip);
133173
}
134174
}
175+
176+
viewGroup.addView(entry);
177+
updateSegmentedStyle();
135178
});
136179
}
180+
181+
private void updateSegmentedStyle() {
182+
for (int i = 0; i < viewGroup.getChildCount(); i++) {
183+
View child = viewGroup.getChildAt(i);
184+
if (child instanceof com.google.android.material.listitem.ListItemLayout) {
185+
((com.google.android.material.listitem.ListItemLayout) child).updateAppearance(i, viewGroup.getChildCount());
186+
}
187+
}
188+
}
137189
}
138190
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorPrimary"
5+
android:viewportWidth="960"
6+
android:viewportHeight="960">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M424,552L338,466Q327,455 310,455Q293,455 282,466Q271,477 271,494Q271,511 282,522L396,636Q408,648 424,648Q440,648 452,636L678,410Q689,399 689,382Q689,365 678,354Q667,343 650,343Q633,343 622,354L424,552ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z" />
10+
</vector>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:tint="?attr/colorError"
5+
android:viewportWidth="960"
6+
android:viewportHeight="960">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M480,536L596,652Q607,663 624,663Q641,663 652,652Q663,641 663,624Q663,607 652,596L536,480L652,364Q663,353 663,336Q663,319 652,308Q641,297 624,297Q607,297 596,308L480,424L364,308Q353,297 336,297Q319,297 308,308Q297,319 297,336Q297,353 308,364L424,480L308,596Q297,607 297,624Q297,641 308,652Q319,663 336,663Q353,663 364,652L480,536ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z" />
10+
</vector>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:autoMirrored="true"
5+
android:tint="?attr/colorOnPrimaryContainer"
6+
android:viewportWidth="960"
7+
android:viewportHeight="960">
8+
<path
9+
android:fillColor="@android:color/white"
10+
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L440,120Q457,120 468.5,131.5Q480,143 480,160Q480,177 468.5,188.5Q457,200 440,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L760,760Q760,760 760,760Q760,760 760,760L760,520Q760,503 771.5,491.5Q783,480 800,480Q817,480 828.5,491.5Q840,503 840,520L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM760,256L416,600Q405,611 388,611Q371,611 360,600Q349,589 349,572Q349,555 360,544L704,200L600,200Q583,200 571.5,188.5Q560,177 560,160Q560,143 571.5,131.5Q583,120 600,120L800,120Q817,120 828.5,131.5Q840,143 840,160L840,360Q840,377 828.5,388.5Q817,400 800,400Q783,400 771.5,388.5Q760,377 760,360L760,256Z" />
11+
</vector>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<selector xmlns:android="http://schemas.android.com/apk/res/android">
2+
<item android:drawable="@drawable/ic_allow" android:state_activated="true" />
3+
<item android:drawable="@drawable/ic_deny" />
4+
</selector>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:app="http://schemas.android.com/apk/res-auto"
3+
style="@style/Widget.Material3.Chip.Assist"
4+
android:layout_width="wrap_content"
5+
android:layout_height="wrap_content"
6+
android:textColor="?attr/colorOnSecondaryContainer"
7+
app:chipBackgroundColor="?attr/colorSecondaryContainer"
8+
app:chipStrokeWidth="0dp" />

play-services-core/microg-ui-tools/src/main/res/layout/self_check_entry.xml

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@
1212
android:id="@+id/material_card_view"
1313
android:layout_width="match_parent"
1414
android:layout_height="wrap_content"
15-
android:checkable="false"
1615
app:cardBackgroundColor="?attr/colorSurfaceContainer">
1716

1817
<androidx.constraintlayout.widget.ConstraintLayout
1918
android:layout_width="match_parent"
2019
android:layout_height="wrap_content"
21-
android:paddingVertical="?attr/listPreferredItemPaddingEnd"
20+
android:paddingVertical="16dp"
2221
android:paddingStart="?attr/listPreferredItemPaddingStart"
23-
android:paddingEnd="8dp">
22+
android:paddingEnd="?attr/listPreferredItemPaddingEnd">
2423

2524
<com.google.android.material.textview.MaterialTextView
2625
android:id="@+id/self_check_name"
2726
android:layout_width="0dp"
2827
android:layout_height="wrap_content"
28+
android:maxLines="2"
2929
android:textAppearance="?attr/textAppearanceTitleMedium"
3030
app:layout_constraintBottom_toTopOf="@+id/self_check_resolution"
31-
app:layout_constraintEnd_toStartOf="@+id/self_check_result"
31+
app:layout_constraintEnd_toStartOf="@+id/self_check_result_icon"
3232
app:layout_constraintHorizontal_chainStyle="spread"
3333
app:layout_constraintStart_toStartOf="parent"
3434
app:layout_constraintTop_toTopOf="parent"
@@ -39,20 +39,35 @@
3939
android:id="@+id/self_check_resolution"
4040
android:layout_width="0dp"
4141
android:layout_height="wrap_content"
42+
android:layout_marginTop="2dp"
43+
android:maxLines="10"
4244
android:textAppearance="?attr/textAppearanceBodyMedium"
4345
android:textColor="?android:textColorSecondary"
44-
app:layout_constraintBottom_toBottomOf="parent"
46+
app:layout_constraintBottom_toTopOf="@+id/self_check_chip_group"
4547
app:layout_constraintEnd_toEndOf="@id/self_check_name"
4648
app:layout_constraintStart_toStartOf="@id/self_check_name"
4749
app:layout_constraintTop_toBottomOf="@id/self_check_name"
4850
tools:text="@string/self_check_desc" />
4951

50-
<com.google.android.material.checkbox.MaterialCheckBox
51-
android:id="@+id/self_check_result"
52+
<com.google.android.material.chip.ChipGroup
53+
android:id="@+id/self_check_chip_group"
54+
android:layout_width="0dp"
55+
android:layout_height="wrap_content"
56+
android:layout_marginTop="8dp"
57+
android:visibility="gone"
58+
app:chipSpacingVertical="4dp"
59+
app:layout_constraintBottom_toBottomOf="parent"
60+
app:layout_constraintEnd_toEndOf="@id/self_check_name"
61+
app:layout_constraintStart_toStartOf="@id/self_check_name"
62+
app:layout_constraintTop_toBottomOf="@id/self_check_resolution" />
63+
64+
<com.google.android.material.imageview.ShapeableImageView
65+
android:id="@+id/self_check_result_icon"
5266
android:layout_width="wrap_content"
5367
android:layout_height="wrap_content"
54-
android:clickable="false"
55-
android:focusable="false"
68+
android:importantForAccessibility="no"
69+
android:paddingStart="8dp"
70+
android:src="@drawable/ic_self_check_result"
5671
app:layout_constraintBottom_toBottomOf="parent"
5772
app:layout_constraintEnd_toEndOf="parent"
5873
app:layout_constraintTop_toTopOf="parent" />

0 commit comments

Comments
 (0)