Update SafetyNet check UI

This commit is contained in:
topjohnwu 2017-05-20 03:04:14 +08:00
parent e69b99f089
commit 9ef798f534
21 changed files with 367 additions and 192 deletions

View File

@ -13,6 +13,7 @@ import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo; import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.superuser.Policy; import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap; import com.topjohnwu.magisk.utils.ValueSortedMap;
@ -46,7 +47,7 @@ public class MagiskManager extends Application {
public int remoteMagiskVersionCode = -1; public int remoteMagiskVersionCode = -1;
public String magiskLink; public String magiskLink;
public String releaseNoteLink; public String releaseNoteLink;
public int SNCheckResult = -1; public SafetyNetHelper.Result SNCheckResult;
public String bootBlock = null; public String bootBlock = null;
public boolean isSuClient = false; public boolean isSuClient = false;
public String suVersion = null; public String suVersion = null;

View File

@ -1,12 +1,16 @@
package com.topjohnwu.magisk; package com.topjohnwu.magisk;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@ -41,25 +45,28 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
@BindView(R.id.root_status_icon) ImageView rootStatusIcon; @BindView(R.id.root_status_icon) ImageView rootStatusIcon;
@BindView(R.id.root_status) TextView rootStatusText; @BindView(R.id.root_status) TextView rootStatusText;
@BindView(R.id.safetyNet_container) View safetyNetContainer; @BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
@BindView(R.id.safetyNet_icon) ImageView safetyNetIcon;
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText; @BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress; @BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
@BindView(R.id.expand_layout) LinearLayout expandLayout;
@BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
@BindView(R.id.cts_status) TextView ctsStatusText;
@BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
@BindView(R.id.basic_status) TextView basicStatusText;
@BindColor(R.color.red500) int colorBad; @BindColor(R.color.red500) int colorBad;
@BindColor(R.color.green500) int colorOK; @BindColor(R.color.green500) int colorOK;
@BindColor(R.color.yellow500) int colorWarn; @BindColor(R.color.yellow500) int colorWarn;
@BindColor(R.color.grey500) int colorNeutral; @BindColor(R.color.grey500) int colorNeutral;
@BindColor(R.color.blue500) int colorInfo; @BindColor(R.color.blue500) int colorInfo;
@BindColor(android.R.color.transparent) int trans;
@OnClick(R.id.safetyNet_container) @OnClick(R.id.safetyNet_title)
public void safetyNet() { public void safetyNet() {
safetyNetProgress.setVisibility(View.VISIBLE); safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetContainer.setBackgroundColor(trans); safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetIcon.setImageResource(0);
safetyNetStatusText.setText(R.string.checking_safetyNet_status); safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(magiskManager); Utils.checkSafetyNet(getActivity());
collapse();
} }
public void gotoInstall() { public void gotoInstall() {
@ -68,8 +75,9 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
} }
} }
private int defaultColor;
private MagiskManager magiskManager; private MagiskManager magiskManager;
private static int expandHeight = 0;
private static boolean mExpanded = false;
@Nullable @Nullable
@Override @Override
@ -78,20 +86,33 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
unbinder = ButterKnife.bind(this, v); unbinder = ButterKnife.bind(this, v);
magiskManager = getApplication(); magiskManager = getApplication();
defaultColor = magiskUpdateText.getCurrentTextColor(); expandLayout.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (expandHeight == 0) {
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
expandLayout.measure(widthSpec, heightSpec);
expandHeight = expandLayout.getMeasuredHeight();
}
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
setExpanded();
return true;
}
});
mSwipeRefreshLayout.setOnRefreshListener(() -> { mSwipeRefreshLayout.setOnRefreshListener(() -> {
magiskUpdateText.setText(R.string.checking_for_updates); magiskUpdateText.setText(R.string.checking_for_updates);
magiskCheckUpdatesProgress.setVisibility(View.VISIBLE); magiskCheckUpdatesProgress.setVisibility(View.VISIBLE);
magiskUpdateIcon.setVisibility(View.GONE); magiskUpdateIcon.setVisibility(View.GONE);
safetyNetProgress.setVisibility(View.GONE);
safetyNetContainer.setBackgroundColor(colorNeutral);
safetyNetIcon.setImageResource(R.drawable.ic_safetynet);
safetyNetStatusText.setText(R.string.safetyNet_check_text); safetyNetStatusText.setText(R.string.safetyNet_check_text);
safetyNetStatusText.setTextColor(defaultColor);
magiskManager.safetyNetDone.isTriggered = false; magiskManager.safetyNetDone.isTriggered = false;
collapse();
noDialog = false; noDialog = false;
updateUI(); updateUI();
@ -217,37 +238,86 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener<V
private void updateSafetyNetUI() { private void updateSafetyNetUI() {
int image, color; int image, color;
safetyNetProgress.setVisibility(View.GONE); safetyNetProgress.setVisibility(View.GONE);
switch (magiskManager.SNCheckResult) { safetyNetRefreshIcon.setVisibility(View.VISIBLE);
case -3: if (magiskManager.SNCheckResult.failed) {
color = colorNeutral; safetyNetStatusText.setText(magiskManager.SNCheckResult.errmsg);
image = R.drawable.ic_help; collapse();
safetyNetStatusText.setText(R.string.safetyNet_connection_suspended); } else {
break; safetyNetStatusText.setText(R.string.safetyNet_check_success);
case -2: if (magiskManager.SNCheckResult.ctsProfile) {
color = colorNeutral;
image = R.drawable.ic_help;
safetyNetStatusText.setText(R.string.safetyNet_connection_failed);
break;
case -1:
color = colorNeutral;
image = R.drawable.ic_help;
safetyNetStatusText.setText(R.string.safetyNet_error);
break;
case 0:
color = colorBad;
image = R.drawable.ic_cancel;
safetyNetStatusText.setText(R.string.safetyNet_fail);
break;
case 1:
default:
color = colorOK; color = colorOK;
image = R.drawable.ic_check_circle; image = R.drawable.ic_check_circle;
safetyNetStatusText.setText(R.string.safetyNet_pass); } else {
break; color = colorBad;
image = R.drawable.ic_cancel;
}
ctsStatusText.setText("ctsProfile: " + magiskManager.SNCheckResult.ctsProfile);
ctsStatusIcon.setImageResource(image);
ctsStatusIcon.setColorFilter(color);
if (magiskManager.SNCheckResult.basicIntegrity) {
color = colorOK;
image = R.drawable.ic_check_circle;
} else {
color = colorBad;
image = R.drawable.ic_cancel;
}
basicStatusText.setText("basicIntegrity: " + magiskManager.SNCheckResult.basicIntegrity);
basicStatusIcon.setImageResource(image);
basicStatusIcon.setColorFilter(color);
expand();
} }
safetyNetContainer.setBackgroundColor(color); }
safetyNetStatusText.setTextColor(color);
safetyNetIcon.setImageResource(image); private void setExpanded() {
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = mExpanded ? expandHeight : 0;
expandLayout.setLayoutParams(layoutParams);
expandLayout.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
}
private void expand() {
if (mExpanded) return;
expandLayout.setVisibility(View.VISIBLE);
ValueAnimator mAnimator = slideAnimator(0, expandHeight);
mAnimator.start();
mExpanded = true;
}
private void collapse() {
if (!mExpanded) return;
int finalHeight = expandLayout.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animator) {
expandLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationCancel(Animator animator) {}
@Override
public void onAnimationRepeat(Animator animator) {}
});
mAnimator.start();
mExpanded = false;
}
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator -> {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
layoutParams.height = value;
expandLayout.setLayoutParams(layoutParams);
});
return animator;
} }
} }

View File

@ -1,15 +1,16 @@
package com.topjohnwu.magisk.utils; package com.topjohnwu.magisk.utils;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Base64; import android.util.Base64;
import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Status; import com.google.android.gms.common.api.Status;
import com.google.android.gms.safetynet.SafetyNet; import com.google.android.gms.safetynet.SafetyNet;
import com.topjohnwu.magisk.R;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -20,39 +21,49 @@ public abstract class SafetyNetHelper
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks { implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mGoogleApiClient; private GoogleApiClient mGoogleApiClient;
private Result ret;
protected FragmentActivity mActivity;
public SafetyNetHelper(Context context) { public SafetyNetHelper(FragmentActivity activity) {
mGoogleApiClient = new GoogleApiClient.Builder(context) ret = new Result();
mActivity = activity;
mGoogleApiClient = new GoogleApiClient.Builder(activity)
.enableAutoManage(activity, this)
.addApi(SafetyNet.API) .addApi(SafetyNet.API)
.addConnectionCallbacks(this) .addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build(); .build();
} }
@Override // Entry point to start test
public void onConnectionFailed(@NonNull ConnectionResult result) {
Logger.dev("SN: Google API fail");
handleResults(-2);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.dev("SN: Google API Connected");
safetyNetCheck();
}
@Override
public void onConnectionSuspended(int i) {
Logger.dev("SN: Google API Suspended");
handleResults(-3);
}
public void requestTest() { public void requestTest() {
// Connect Google Service // Connect Google Service
mGoogleApiClient.connect(); mGoogleApiClient.connect();
} }
private void safetyNetCheck() { @Override
public void onConnectionFailed(@NonNull ConnectionResult result) {
Logger.dev("SN: Google API fail");
ret.errmsg = result.getErrorMessage();
handleResults(ret);
}
@Override
public void onConnectionSuspended(int i) {
Logger.dev("SN: Google API Suspended");
switch (i) {
case CAUSE_NETWORK_LOST:
ret.errmsg = mActivity.getString(R.string.safetyNet_network_loss);
break;
case CAUSE_SERVICE_DISCONNECTED:
ret.errmsg = mActivity.getString(R.string.safetyNet_service_disconnected);
break;
}
handleResults(ret);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.dev("SN: Google API Connected");
// Create nonce // Create nonce
byte[] nonce = new byte[24]; byte[] nonce = new byte[24];
new SecureRandom().nextBytes(nonce); new SecureRandom().nextBytes(nonce);
@ -68,16 +79,30 @@ public abstract class SafetyNetHelper
Logger.dev("SN: Response: " + json); Logger.dev("SN: Response: " + json);
try { try {
JSONObject decoded = new JSONObject(json); JSONObject decoded = new JSONObject(json);
handleResults(decoded.getBoolean("ctsProfileMatch") ? 1 : 0); ret.ctsProfile = decoded.getBoolean("ctsProfileMatch");
} catch (JSONException ignored) {} ret.basicIntegrity = decoded.getBoolean("basicIntegrity");
ret.failed = false;
} catch (JSONException e) {
ret.errmsg = mActivity.getString(R.string.safetyNet_res_invalid);
}
} else { } else {
Logger.dev("SN: No response"); Logger.dev("SN: No response");
handleResults(-1); ret.errmsg = mActivity.getString(R.string.safetyNet_no_response);
} }
// Disconnect // Disconnect
mGoogleApiClient.stopAutoManage(mActivity);
mGoogleApiClient.disconnect(); mGoogleApiClient.disconnect();
handleResults(ret);
}); });
} }
public abstract void handleResults(int i); // Callback function to save the results
public abstract void handleResults(Result result);
public static class Result {
public boolean failed = true;
public String errmsg;
public boolean ctsProfile = false;
public boolean basicIntegrity = false;
}
} }

View File

@ -13,6 +13,7 @@ import android.os.Environment;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils; import android.text.TextUtils;
import android.widget.Toast; import android.widget.Toast;
@ -144,12 +145,12 @@ public class Utils {
return (MagiskManager) context.getApplicationContext(); return (MagiskManager) context.getApplicationContext();
} }
public static void checkSafetyNet(MagiskManager magiskManager) { public static void checkSafetyNet(FragmentActivity activity) {
new SafetyNetHelper(magiskManager) { new SafetyNetHelper(activity) {
@Override @Override
public void handleResults(int i) { public void handleResults(Result result) {
magiskManager.SNCheckResult = i; getMagiskManager(mActivity).SNCheckResult = result;
magiskManager.safetyNetDone.trigger(); getMagiskManager(mActivity).safetyNetDone.trigger();
} }
}.requestTest(); }.requestTest();
} }

View File

@ -21,170 +21,244 @@
android:orientation="vertical"> android:orientation="vertical">
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
style="?attr/cardStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip" android:layout_marginLeft="5dp"
android:layout_marginRight="5dip" android:layout_marginRight="5dp"
android:layout_marginTop="6dp" android:layout_marginTop="4dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"> app:cardUseCompatPadding="true">
<LinearLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:gravity="center"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/magisk_check_updates_progress"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_margin="15dp" />
<ImageView <ImageView
android:id="@+id/magisk_update_icon" android:id="@+id/magisk_update_icon"
android:layout_width="25dp" android:layout_width="25dp"
android:layout_height="25dp" android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_margin="15dp" android:layout_margin="15dp"
android:layout_toStartOf="@+id/magisk_update_status"
android:src="@drawable/ic_refresh"
android:visibility="gone" /> android:visibility="gone" />
<ProgressBar
android:id="@+id/magisk_check_updates_progress"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_margin="15dp"
android:layout_toStartOf="@+id/magisk_update_status" />
<TextView <TextView
android:id="@+id/magisk_update_status" android:id="@+id/magisk_update_status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="225dp" android:layout_centerHorizontal="true"
android:layout_gravity="center" android:layout_centerVertical="true"
android:gravity="center" android:gravity="center"
android:minWidth="225dp"
android:padding="6dp" android:padding="6dp"
android:textStyle="bold" android:text="@string/checking_for_updates"
android:text="@string/checking_for_updates" /> android:textStyle="bold" />
</LinearLayout> </RelativeLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
style="?attr/cardStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip" android:layout_marginLeft="5dp"
android:layout_marginRight="5dip" android:layout_marginRight="5dp"
android:layout_marginTop="6dp" android:layout_marginTop="4dp"
style="?attr/cardStyle"
app:cardUseCompatPadding="true"> app:cardUseCompatPadding="true">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:orientation="vertical">
android:orientation="horizontal">
<ImageView <RelativeLayout
android:id="@+id/magisk_status_icon" android:layout_width="match_parent"
android:layout_width="25dp" android:layout_height="match_parent"
android:layout_height="25dp" android:layout_marginBottom="5dp"
android:layout_margin="15dp" /> android:layout_marginTop="15dp"
android:orientation="horizontal">
<TextView <ImageView
android:id="@+id/magisk_version" android:id="@+id/magisk_status_icon"
android:layout_width="wrap_content" android:layout_width="25dp"
android:layout_height="wrap_content" android:layout_height="25dp"
android:minWidth="225dp" android:layout_centerVertical="true"
android:layout_gravity="center" android:layout_marginEnd="15dp"
android:gravity="center" android:layout_marginStart="15dp"
android:padding="6dp" android:layout_toStartOf="@+id/magisk_version" />
android:textStyle="bold" />
<TextView
android:id="@+id/magisk_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="225dp"
android:padding="6dp"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="15dp"
android:layout_marginTop="5dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/root_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_marginEnd="15dp"
android:layout_marginStart="15dp"
android:layout_toStartOf="@+id/root_status" />
<TextView
android:id="@+id/root_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="225dp"
android:padding="6dp"
android:textStyle="bold" />
</RelativeLayout>
</LinearLayout> </LinearLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>
<android.support.v7.widget.CardView <android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="6dp"
style="?attr/cardStyle" style="?attr/cardStyle"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/root_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_margin="15dp" />
<TextView
android:id="@+id/root_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="225dp"
android:layout_gravity="center"
android:gravity="center"
android:padding="6dp"
android:textStyle="bold" />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="@+id/safetyNetView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_marginLeft="5dip" android:layout_marginEnd="5dp"
android:layout_marginRight="5dip" android:layout_marginStart="4dp"
android:layout_marginTop="6dp" android:layout_marginTop="5dp"
style="?attr/cardStyle" android:minHeight="?android:attr/listPreferredItemHeight"
app:cardUseCompatPadding="true"> app:cardCornerRadius="@dimen/card_corner_radius"
app:cardElevation="@dimen/card_elevation">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<FrameLayout <RelativeLayout
android:id="@+id/safetyNet_container" android:id="@+id/safetyNet_title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="100dp" android:layout_height="match_parent">
android:foregroundGravity="center"
android:orientation="vertical"
android:background="@color/grey500">
<ImageView <ImageView
android:id="@+id/safetyNet_icon" android:id="@+id/safetyNet_refresh"
android:layout_width="84dp" android:layout_width="25dp"
android:layout_height="84dp" android:layout_height="25dp"
android:layout_gravity="center" android:layout_centerVertical="true"
android:src="@drawable/ic_safetynet"/> android:layout_margin="15dp"
android:layout_toStartOf="@+id/safetyNet_status"
android:src="@drawable/ic_refresh" />
<ProgressBar <ProgressBar
android:id="@+id/safetyNet_check_progress" android:id="@+id/safetyNet_check_progress"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_margin="15dp"
android:layout_toStartOf="@+id/safetyNet_status"
android:visibility="gone" />
<TextView
android:id="@+id/safetyNet_status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_centerHorizontal="true"
android:visibility="gone"/> android:layout_centerVertical="true"
android:gravity="center"
android:minWidth="175dp"
android:padding="6dp"
android:text="@string/safetyNet_check_text"
android:textStyle="bold" />
</FrameLayout> </RelativeLayout>
<TextView <LinearLayout
android:id="@+id/safetyNet_status" android:id="@+id/expand_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:orientation="vertical"
android:gravity="center" android:paddingEnd="10dp"
android:padding="6dp" android:paddingStart="10dp">
android:textStyle="bold"
android:text="@string/safetyNet_check_text" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/cts_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginBottom="5dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp" />
<TextView
android:id="@+id/cts_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="150dp"
android:padding="6dp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/basic_status_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_margin="10dp" />
<TextView
android:id="@+id/basic_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="150dp"
android:padding="6dp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -110,7 +110,7 @@
<string name="keep_dm_verity">إبقاء dm-verity</string> <string name="keep_dm_verity">إبقاء dm-verity</string>
<string name="root_error">مروت لكن لا يوجد إذن الروت، غير مسموح به؟</string> <string name="root_error">مروت لكن لا يوجد إذن الروت، غير مسموح به؟</string>
<string name="root_info_warning">وظائف محدودة إلى حد كبير</string> <string name="root_info_warning">وظائف محدودة إلى حد كبير</string>
<string name="safetyNet_error">تعذر التحقق من SafetyNet، لا يوجد إنترنت؟</string> <string name="safetyNet_no_response">تعذر التحقق من SafetyNet، لا يوجد إنترنت؟</string>
<string name="safetyNet_pass">SafetyNet تخطى</string> <string name="safetyNet_pass">SafetyNet تخطى</string>
<string name="safetyNet_fail">فشل SafetyNet: عدم تطابق التشكيل الجانبي CTS</string> <string name="safetyNet_fail">فشل SafetyNet: عدم تطابق التشكيل الجانبي CTS</string>
<string name="status">الحالة</string> <string name="status">الحالة</string>

View File

@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">Kontrola stavu SafetyNet…</string> <string name="checking_safetyNet_status">Kontrola stavu SafetyNet…</string>
<string name="safetyNet_connection_failed">Nelze se spojit s Google API</string> <string name="safetyNet_connection_failed">Nelze se spojit s Google API</string>
<string name="safetyNet_connection_suspended">Spojení s Google API bylo přerušeno</string> <string name="safetyNet_connection_suspended">Spojení s Google API bylo přerušeno</string>
<string name="safetyNet_error">Nelze zkontrolovat SafetyNet. Jste připojeni k Internetu?</string> <string name="safetyNet_no_response">Nelze zkontrolovat SafetyNet. Jste připojeni k Internetu?</string>
<string name="safetyNet_fail">SafetyNet dopadl neúspěšně: CTS profile mismatch</string> <string name="safetyNet_fail">SafetyNet dopadl neúspěšně: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Schváleno</string> <string name="safetyNet_pass">SafetyNet Schváleno</string>
<string name="root_info_warning">Funkčnost omezena</string> <string name="root_info_warning">Funkčnost omezena</string>

View File

@ -30,7 +30,7 @@
<string name="checking_safetyNet_status">Prüfe SafetyNet-Status…</string> <string name="checking_safetyNet_status">Prüfe SafetyNet-Status…</string>
<string name="safetyNet_connection_failed">Verbindung zur Google-API fehlgeschlagen</string> <string name="safetyNet_connection_failed">Verbindung zur Google-API fehlgeschlagen</string>
<string name="safetyNet_connection_suspended">Verbindung zur Google-API wurde ausgesetzt</string> <string name="safetyNet_connection_suspended">Verbindung zur Google-API wurde ausgesetzt</string>
<string name="safetyNet_error">SafetyNet-Status konnte nicht geprüft werden. Ist eine Internetverbindung verfügbar?</string> <string name="safetyNet_no_response">SafetyNet-Status konnte nicht geprüft werden. Ist eine Internetverbindung verfügbar?</string>
<string name="safetyNet_fail">SafetyNet nicht bestanden: \"CTS profile mismatch\"</string> <string name="safetyNet_fail">SafetyNet nicht bestanden: \"CTS profile mismatch\"</string>
<string name="safetyNet_pass">SafetyNet bestanden</string> <string name="safetyNet_pass">SafetyNet bestanden</string>
<string name="root_info_warning">Funktionalität stark eingeschränkt</string> <string name="root_info_warning">Funktionalität stark eingeschränkt</string>

View File

@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">Comprobando estado de SafetyNet…</string> <string name="checking_safetyNet_status">Comprobando estado de SafetyNet…</string>
<string name="safetyNet_connection_failed">No puede conectar con la API de Google</string> <string name="safetyNet_connection_failed">No puede conectar con la API de Google</string>
<string name="safetyNet_connection_suspended">La conexión con la API de Google API fue suspendida</string> <string name="safetyNet_connection_suspended">La conexión con la API de Google API fue suspendida</string>
<string name="safetyNet_error">No puede comprobar SafetyNet, ¿No tiene internet?</string> <string name="safetyNet_no_response">No puede comprobar SafetyNet, ¿No tiene internet?</string>
<string name="safetyNet_fail">SafetyNet: Error, no coincide el perfil CTS</string> <string name="safetyNet_fail">SafetyNet: Error, no coincide el perfil CTS</string>
<string name="safetyNet_pass">SafetyNet: Correcto</string> <string name="safetyNet_pass">SafetyNet: Correcto</string>
<string name="root_info_warning">Funcionalidad enormemente limitada</string> <string name="root_info_warning">Funcionalidad enormemente limitada</string>

View File

@ -25,7 +25,7 @@
<string name="checking_safetyNet_status">Vérification de l\'état de SafetyNet…</string> <string name="checking_safetyNet_status">Vérification de l\'état de SafetyNet…</string>
<string name="safetyNet_connection_failed">Impossible de se connecter à l\'API Google</string> <string name="safetyNet_connection_failed">Impossible de se connecter à l\'API Google</string>
<string name="safetyNet_connection_suspended">La connexion à l\'API Google a été suspendue</string> <string name="safetyNet_connection_suspended">La connexion à l\'API Google a été suspendue</string>
<string name="safetyNet_error">Impossible de contrôler SafetyNet, pas d\'Internet?</string> <string name="safetyNet_no_response">Impossible de contrôler SafetyNet, pas d\'Internet?</string>
<string name="safetyNet_fail">Échec SafetyNet: erreur de profil CTS</string> <string name="safetyNet_fail">Échec SafetyNet: erreur de profil CTS</string>
<string name="safetyNet_pass">SafetyNet réussi</string> <string name="safetyNet_pass">SafetyNet réussi</string>
<string name="root_info_warning">Fonctionnalités largement limitées</string> <string name="root_info_warning">Fonctionnalités largement limitées</string>

View File

@ -28,7 +28,7 @@
<string name="checking_safetyNet_status">Controllo SafetyNet</string> <string name="checking_safetyNet_status">Controllo SafetyNet</string>
<string name="safetyNet_connection_failed">Impossibile collegarsi alle API Google</string> <string name="safetyNet_connection_failed">Impossibile collegarsi alle API Google</string>
<string name="safetyNet_connection_suspended">Connessione alle API Google sospesa</string> <string name="safetyNet_connection_suspended">Connessione alle API Google sospesa</string>
<string name="safetyNet_error">Impossibile controllare SafetyNet. Nessuna connessione internet?</string> <string name="safetyNet_no_response">Impossibile controllare SafetyNet. Nessuna connessione internet?</string>
<string name="safetyNet_fail">Errore SafetyNet. Il profilo CTS non corrisponde</string> <string name="safetyNet_fail">Errore SafetyNet. Il profilo CTS non corrisponde</string>
<string name="safetyNet_pass">Controllo SafetyNet OK</string> <string name="safetyNet_pass">Controllo SafetyNet OK</string>
<string name="root_info_warning">Funzionalità molto limitata</string> <string name="root_info_warning">Funzionalità molto limitata</string>

View File

@ -28,7 +28,7 @@
<string name="checking_safetyNet_status">SafetyNet Statusをチェック中…</string> <string name="checking_safetyNet_status">SafetyNet Statusをチェック中…</string>
<string name="safetyNet_connection_failed">Google APIに接続できませんでした</string> <string name="safetyNet_connection_failed">Google APIに接続できませんでした</string>
<string name="safetyNet_connection_suspended">Google APIへの接続が中断されました</string> <string name="safetyNet_connection_suspended">Google APIへの接続が中断されました</string>
<string name="safetyNet_error">SafetyNetをチェックできませんでした。インターネットに接続されていますか</string> <string name="safetyNet_no_response">SafetyNetをチェックできませんでした。インターネットに接続されていますか</string>
<string name="safetyNet_fail">SafetyNet Failed: CTSプロファイルが不一致</string> <string name="safetyNet_fail">SafetyNet Failed: CTSプロファイルが不一致</string>
<string name="safetyNet_pass">SafetyNet Passed</string> <string name="safetyNet_pass">SafetyNet Passed</string>
<string name="root_info_warning">機能が大幅に制限されています</string> <string name="root_info_warning">機能が大幅に制限されています</string>

View File

@ -28,7 +28,7 @@
<string name="checking_safetyNet_status">SafetyNet 상태 확인 중…</string> <string name="checking_safetyNet_status">SafetyNet 상태 확인 중…</string>
<string name="safetyNet_connection_failed">Google API에 연결할 수 없음</string> <string name="safetyNet_connection_failed">Google API에 연결할 수 없음</string>
<string name="safetyNet_connection_suspended">Google API에 대한 연결이 일시 중지됨</string> <string name="safetyNet_connection_suspended">Google API에 대한 연결이 일시 중지됨</string>
<string name="safetyNet_error">SafetyNet 체크 실패. 인터넷 연결을 확인하세요.</string> <string name="safetyNet_no_response">SafetyNet 체크 실패. 인터넷 연결을 확인하세요.</string>
<string name="safetyNet_fail">SafetyNet 실패: CTS 프로필 불일치</string> <string name="safetyNet_fail">SafetyNet 실패: CTS 프로필 불일치</string>
<string name="safetyNet_pass">SafetyNet 통과</string> <string name="safetyNet_pass">SafetyNet 통과</string>
<string name="root_info_warning">기능이 크게 제한됨</string> <string name="root_info_warning">기능이 크게 제한됨</string>

View File

@ -31,7 +31,7 @@
<string name="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string> <string name="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string>
<string name="safetyNet_connection_failed">Nie można połączyć się z Google API</string> <string name="safetyNet_connection_failed">Nie można połączyć się z Google API</string>
<string name="safetyNet_connection_suspended">Połączenie z Google API zostało zawieszone</string> <string name="safetyNet_connection_suspended">Połączenie z Google API zostało zawieszone</string>
<string name="safetyNet_error">Nie można sprawdzić SafetyNet bez internetu</string> <string name="safetyNet_no_response">Nie można sprawdzić SafetyNet bez internetu</string>
<string name="safetyNet_fail">Błąd SafetyNet: Niezgodność profilu CTS</string> <string name="safetyNet_fail">Błąd SafetyNet: Niezgodność profilu CTS</string>
<string name="safetyNet_pass">SafetyNet Poprawny</string> <string name="safetyNet_pass">SafetyNet Poprawny</string>
<string name="root_info_warning">Funkcjonalność znacznie ograniczona</string> <string name="root_info_warning">Funkcjonalność znacznie ograniczona</string>

View File

@ -31,7 +31,7 @@
<string name="checking_safetyNet_status">Checando status do SafetyNet…</string> <string name="checking_safetyNet_status">Checando status do SafetyNet…</string>
<string name="safetyNet_connection_failed">Não é possível conectar-se à API do Google</string> <string name="safetyNet_connection_failed">Não é possível conectar-se à API do Google</string>
<string name="safetyNet_connection_suspended">A conexão com API do Google foi suspensa</string> <string name="safetyNet_connection_suspended">A conexão com API do Google foi suspensa</string>
<string name="safetyNet_error">Não é possível verificar o SafetyNet, sem Internet?</string> <string name="safetyNet_no_response">Não é possível verificar o SafetyNet, sem Internet?</string>
<string name="safetyNet_fail">SafetyNet Falhou: CTS profile mismatch</string> <string name="safetyNet_fail">SafetyNet Falhou: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Passado</string> <string name="safetyNet_pass">SafetyNet Passado</string>
<string name="root_info_warning">Funcionalidade muito limitada</string> <string name="root_info_warning">Funcionalidade muito limitada</string>

View File

@ -25,7 +25,7 @@
<string name="checking_safetyNet_status">Проверка статуса SafetyNet…</string> <string name="checking_safetyNet_status">Проверка статуса SafetyNet…</string>
<string name="safetyNet_connection_failed">Невозможно соединиться с API Google</string> <string name="safetyNet_connection_failed">Невозможно соединиться с API Google</string>
<string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string> <string name="safetyNet_connection_suspended">Соединение с API Google было приостановлено</string>
<string name="safetyNet_error">Невозможно выполнить проверку SafetyNet, нет соединения?</string> <string name="safetyNet_no_response">Невозможно выполнить проверку SafetyNet, нет соединения?</string>
<string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string> <string name="safetyNet_fail">SafetyNet не пройден: несовпадение профиля CTS</string>
<string name="safetyNet_pass">SafetyNet пройден</string> <string name="safetyNet_pass">SafetyNet пройден</string>
<string name="root_info_warning">Функциональность значительно ограничена</string> <string name="root_info_warning">Функциональность значительно ограничена</string>

View File

@ -25,7 +25,7 @@
<string name="checking_safetyNet_status">SafetyNet durumu kontrol ediliyor…</string> <string name="checking_safetyNet_status">SafetyNet durumu kontrol ediliyor…</string>
<string name="safetyNet_connection_failed">"Google API'ye bağlanılamıyor"</string> <string name="safetyNet_connection_failed">"Google API'ye bağlanılamıyor"</string>
<string name="safetyNet_connection_suspended">Google API bağlantısı askıya alındı</string> <string name="safetyNet_connection_suspended">Google API bağlantısı askıya alındı</string>
<string name="safetyNet_error">SafetyNet kontrol edilemiyor, İnternet yok mu?</string> <string name="safetyNet_no_response">SafetyNet kontrol edilemiyor, İnternet yok mu?</string>
<string name="safetyNet_fail">SafetyNet başarısız: CTS profili uyumsuzluğu</string> <string name="safetyNet_fail">SafetyNet başarısız: CTS profili uyumsuzluğu</string>
<string name="safetyNet_pass">SafetyNet Geçti</string> <string name="safetyNet_pass">SafetyNet Geçti</string>
<string name="root_info_warning">İşlevsellik çok sınırlıdır</string> <string name="root_info_warning">İşlevsellik çok sınırlıdır</string>

View File

@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">Đang kiểm tra trạng thái SafetyNet…</string> <string name="checking_safetyNet_status">Đang kiểm tra trạng thái SafetyNet…</string>
<string name="safetyNet_connection_failed">Không thể kết nối với API của Google</string> <string name="safetyNet_connection_failed">Không thể kết nối với API của Google</string>
<string name="safetyNet_connection_suspended">Kết nối với API của Google đã dừng</string> <string name="safetyNet_connection_suspended">Kết nối với API của Google đã dừng</string>
<string name="safetyNet_error">Không thể kiểm tra SafetyNet, không có Internet?</string> <string name="safetyNet_no_response">Không thể kiểm tra SafetyNet, không có Internet?</string>
<string name="safetyNet_fail">SafetyNet thất bại: cấu hình CTS không phù hợp</string> <string name="safetyNet_fail">SafetyNet thất bại: cấu hình CTS không phù hợp</string>
<string name="safetyNet_pass">SafetyNet thành công</string> <string name="safetyNet_pass">SafetyNet thành công</string>
<string name="root_info_warning">Tính năng bị hạn chế rất nhiều</string> <string name="root_info_warning">Tính năng bị hạn chế rất nhiều</string>

View File

@ -28,7 +28,7 @@
<string name="checking_safetyNet_status">正在检查 SafetyNet 状态…</string> <string name="checking_safetyNet_status">正在检查 SafetyNet 状态…</string>
<string name="safetyNet_connection_failed">无法连接至 Google API</string> <string name="safetyNet_connection_failed">无法连接至 Google API</string>
<string name="safetyNet_connection_suspended">与 Google API 的连接已暂停</string> <string name="safetyNet_connection_suspended">与 Google API 的连接已暂停</string>
<string name="safetyNet_error">无法检查 SafetyNet没有网络连接</string> <string name="safetyNet_no_response">无法检查 SafetyNet没有网络连接</string>
<string name="safetyNet_fail">SafetyNet 失败CTS 配置文件不匹配</string> <string name="safetyNet_fail">SafetyNet 失败CTS 配置文件不匹配</string>
<string name="safetyNet_pass">SafetyNet 已通过</string> <string name="safetyNet_pass">SafetyNet 已通过</string>
<string name="root_info_warning">功能严重受限</string> <string name="root_info_warning">功能严重受限</string>

View File

@ -27,7 +27,7 @@
<string name="checking_safetyNet_status">正在檢查 SafetyNet 狀態…</string> <string name="checking_safetyNet_status">正在檢查 SafetyNet 狀態…</string>
<string name="safetyNet_connection_failed">無法連接至 Google API</string> <string name="safetyNet_connection_failed">無法連接至 Google API</string>
<string name="safetyNet_connection_suspended">與 Google API 的連接已暫停</string> <string name="safetyNet_connection_suspended">與 Google API 的連接已暫停</string>
<string name="safetyNet_error">無法檢查 SafetyNet沒有網絡連線</string> <string name="safetyNet_no_response">無法檢查 SafetyNet沒有網絡連線</string>
<string name="safetyNet_fail">SafetyNet 失敗CTS 配置文件不匹配</string> <string name="safetyNet_fail">SafetyNet 失敗CTS 配置文件不匹配</string>
<string name="safetyNet_pass">SafetyNet 已通過</string> <string name="safetyNet_pass">SafetyNet 已通過</string>
<string name="root_info_warning">功能嚴重受限</string> <string name="root_info_warning">功能嚴重受限</string>

View File

@ -29,11 +29,15 @@
<string name="proper_root">Properly rooted</string> <string name="proper_root">Properly rooted</string>
<string name="safetyNet_check_text">Tap to start SafetyNet check</string> <string name="safetyNet_check_text">Tap to start SafetyNet check</string>
<string name="checking_safetyNet_status">Checking SafetyNet status…</string> <string name="checking_safetyNet_status">Checking SafetyNet status…</string>
<string name="safetyNet_check_success">SafetyNet Check Success</string>
<string name="safetyNet_connection_failed">Cannot connect to Google API</string> <string name="safetyNet_connection_failed">Cannot connect to Google API</string>
<string name="safetyNet_connection_suspended">Connection to Google API was suspended</string> <string name="safetyNet_connection_suspended">Connection to Google API was suspended</string>
<string name="safetyNet_error">Cannot check SafetyNet, no Internet?</string> <string name="safetyNet_no_response">Cannot check SafetyNet, no Internet?</string>
<string name="safetyNet_fail">SafetyNet Failed: CTS profile mismatch</string> <string name="safetyNet_fail">SafetyNet Failed: CTS profile mismatch</string>
<string name="safetyNet_pass">SafetyNet Passed</string> <string name="safetyNet_pass">SafetyNet Passed</string>
<string name="safetyNet_network_loss">Network connection loss</string>
<string name="safetyNet_service_disconnected">Service has been killed</string>
<string name="safetyNet_res_invalid">The response is invalid</string>
<string name="root_info_warning">Functionality greatly limited</string> <string name="root_info_warning">Functionality greatly limited</string>
<!--Install Fragment--> <!--Install Fragment-->