Add crash catch
This commit is contained in:
1 parent
493b70f885
commit
0cbe074fbb
16 files changed
+545
-4
No files matched your search
@@ -31,6 +31,7 @@ public class AppConfig {
|
||||
private static final String DOWNLOAD = "download";
|
||||
private static final String TEMP = "temp";
|
||||
private static final String IMAGE = "image";
|
||||
private static final String CRASH = "crash";
|
||||
|
||||
private static Context sContext;
|
||||
|
||||
@@ -85,6 +86,11 @@ public class AppConfig {
|
||||
return getDirInExternalAppDir(IMAGE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getExternalCrashDir() {
|
||||
return getDirInExternalAppDir(CRASH);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File createExternalTempFile() {
|
||||
return FileUtils.createTempFile(getExternalTempDir(), null);
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import com.hippo.util.PackageUtils;
|
||||
import com.hippo.util.ReadableTime;
|
||||
import com.hippo.yorozuya.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class Crash {
|
||||
|
||||
private static void collectInfo(Context context, FileWriter fw) throws IOException {
|
||||
try {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
|
||||
if (pi != null) {
|
||||
String versionName = pi.versionName == null ? "null" : pi.versionName;
|
||||
String versionCode = String.valueOf(pi.versionCode);
|
||||
fw.write("======== PackageInfo ========\r\n");
|
||||
fw.write("PackageName=");fw.write(pi.packageName);fw.write("\r\n");
|
||||
fw.write("VersionName=");fw.write(versionName);fw.write("\r\n");
|
||||
fw.write("VersionCode=");fw.write(versionCode);fw.write("\r\n");
|
||||
String signature = PackageUtils.getSignature(context, pi.packageName);
|
||||
fw.write("Signature=");fw.write(null != signature ? signature : "null");fw.write("\r\n");
|
||||
fw.write("\r\n");
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
fw.write("======== PackageInfo ========\r\n");
|
||||
fw.write("Can't get package information\r\n");
|
||||
fw.write("\r\n");
|
||||
}
|
||||
|
||||
// Device info
|
||||
fw.write("======== DeviceInfo ========\r\n");
|
||||
fw.write("BOARD=");fw.write(Build.BOARD);fw.write("\r\n");
|
||||
fw.write("BOOTLOADER=");fw.write(Build.BOOTLOADER);fw.write("\r\n");
|
||||
fw.write("CPU_ABI=");fw.write(Build.CPU_ABI);fw.write("\r\n");
|
||||
fw.write("CPU_ABI2=");fw.write(Build.CPU_ABI2);fw.write("\r\n");
|
||||
fw.write("DEVICE=");fw.write(Build.DEVICE);fw.write("\r\n");
|
||||
fw.write("DISPLAY=");fw.write(Build.DISPLAY);fw.write("\r\n");
|
||||
fw.write("FINGERPRINT=");fw.write(Build.FINGERPRINT);fw.write("\r\n");
|
||||
fw.write("HARDWARE=");fw.write(Build.HARDWARE);fw.write("\r\n");
|
||||
fw.write("HOST=");fw.write(Build.HOST);fw.write("\r\n");
|
||||
fw.write("ID=");fw.write(Build.ID);fw.write("\r\n");
|
||||
fw.write("MANUFACTURER=");fw.write(Build.MANUFACTURER);fw.write("\r\n");
|
||||
fw.write("MODEL=");fw.write(Build.MODEL);fw.write("\r\n");
|
||||
fw.write("PRODUCT=");fw.write(Build.PRODUCT);fw.write("\r\n");
|
||||
fw.write("RADIO=");fw.write(Build.getRadioVersion());fw.write("\r\n");
|
||||
fw.write("SERIAL=");fw.write(Build.SERIAL);fw.write("\r\n");
|
||||
fw.write("TAGS=");fw.write(Build.TAGS);fw.write("\r\n");
|
||||
fw.write("TYPE=");fw.write(Build.TYPE);fw.write("\r\n");
|
||||
fw.write("USER=");fw.write(Build.USER);fw.write("\r\n");
|
||||
fw.write("CODENAME=");fw.write(Build.VERSION.CODENAME);fw.write("\r\n");
|
||||
fw.write("INCREMENTAL=");fw.write(Build.VERSION.INCREMENTAL);fw.write("\r\n");
|
||||
fw.write("RELEASE=");fw.write(Build.VERSION.RELEASE);fw.write("\r\n");
|
||||
fw.write("SDK=");fw.write(Integer.toString(Build.VERSION.SDK_INT));fw.write("\r\n");
|
||||
fw.write("\r\n");
|
||||
}
|
||||
|
||||
public static void getThrowableInfo(Throwable t, FileWriter fw) {
|
||||
PrintWriter printWriter = new PrintWriter(fw);
|
||||
t.printStackTrace(printWriter);
|
||||
Throwable cause = t.getCause();
|
||||
while (cause != null) {
|
||||
cause.printStackTrace(printWriter);
|
||||
cause = cause.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveCrashInfo2File(Context context, Throwable ex) {
|
||||
File dir = AppConfig.getExternalCrashDir();
|
||||
if (dir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = "crash-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".log";
|
||||
File file = new File(dir, fileName);
|
||||
|
||||
FileWriter fw = null;
|
||||
try {
|
||||
fw = new FileWriter(file);
|
||||
fw.write("TIME=");fw.write(ReadableTime.getFilenamableTime(System.currentTimeMillis()));fw.write("\r\n");
|
||||
fw.write("\r\n");
|
||||
collectInfo(context, fw);
|
||||
fw.write("======== CrashInfo ========\r\n");
|
||||
getThrowableInfo(ex, fw);
|
||||
fw.write("\r\n");
|
||||
|
||||
fw.flush();
|
||||
|
||||
Settings.putCrashFilename(fileName);
|
||||
} catch (Exception e) {
|
||||
file.delete();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(fw);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasCrashFile() {
|
||||
String filename = Settings.getCrashFilename();
|
||||
if (filename == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File dir = AppConfig.getExternalCrashDir();
|
||||
if (dir == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return new File(dir, filename).isFile();
|
||||
}
|
||||
|
||||
public static String getCrashContent() {
|
||||
String filename = Settings.getCrashFilename();
|
||||
if (filename == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File dir = AppConfig.getExternalCrashDir();
|
||||
if (dir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(dir, filename);
|
||||
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
return IOUtils.readString(is, "UTF-8");
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetCrashFile() {
|
||||
Settings.putCrashFilename(null);
|
||||
}
|
||||
}
|
||||
@@ -49,13 +49,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class EhApplication extends SceneApplication {
|
||||
public class EhApplication extends SceneApplication implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private static final String TAG = EhApplication.class.getSimpleName();
|
||||
|
||||
private static final boolean DEBUG_CONACO = false;
|
||||
private static final boolean DEBUG_NATIVE_MEMORY = false;
|
||||
|
||||
private Thread.UncaughtExceptionHandler mDefaultHandler;
|
||||
|
||||
private final AtomicInteger mIdGenerator = new AtomicInteger();
|
||||
private final SparseArray<Object> mGlobalStuffMap = new SparseArray<>();
|
||||
private EhCookieStore mEhCookieStore;
|
||||
@@ -71,6 +73,10 @@ public class EhApplication extends SceneApplication {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Prepare to catch crash
|
||||
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler(this);
|
||||
|
||||
super.onCreate();
|
||||
|
||||
GetText.initialize(this);
|
||||
@@ -263,4 +269,31 @@ public class EhApplication extends SceneApplication {
|
||||
}
|
||||
return application.mDownloadManager;
|
||||
}
|
||||
|
||||
private boolean handleException(Throwable ex) {
|
||||
if (ex == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ex.printStackTrace();
|
||||
Crash.saveCrashInfo2File(this, ex);
|
||||
return true;
|
||||
} catch (Throwable tr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable ex) {
|
||||
if (!handleException(ex) && mDefaultHandler != null) {
|
||||
mDefaultHandler.uncaughtException(thread, ex);
|
||||
}
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getDeveloperEmail() {
|
||||
return "ehviewersu$gmail.com".replace('$', '@');
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
@@ -486,4 +487,19 @@ public class Settings {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************
|
||||
****** Crash
|
||||
********************/
|
||||
public static final String KEY_CRASH_FILENAME = "crash_filename";
|
||||
public static final String VALUE_CRASH_FILENAME = null;
|
||||
|
||||
public static String getCrashFilename() {
|
||||
return getString(KEY_CRASH_FILENAME, VALUE_CRASH_FILENAME);
|
||||
}
|
||||
|
||||
@SuppressLint("CommitPrefEdits")
|
||||
public static void putCrashFilename(String value) {
|
||||
sSettingsPre.edit().putString(KEY_CRASH_FILENAME, value).commit();
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.hippo.ehviewer.Crash;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhUrlOpener;
|
||||
@@ -43,6 +44,7 @@ import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.ui.scene.AnalyticsScene;
|
||||
import com.hippo.ehviewer.ui.scene.BaseScene;
|
||||
import com.hippo.ehviewer.ui.scene.CookieSignInScene;
|
||||
import com.hippo.ehviewer.ui.scene.CrashScene;
|
||||
import com.hippo.ehviewer.ui.scene.DownloadLabelsScene;
|
||||
import com.hippo.ehviewer.ui.scene.DownloadsScene;
|
||||
import com.hippo.ehviewer.ui.scene.FavoritesScene;
|
||||
@@ -75,7 +77,8 @@ public final class MainActivity extends StageActivity
|
||||
|
||||
public static final int CHECK_STEP_WARNING = 0;
|
||||
public static final int CHECK_STEP_ANALYTICS = 1;
|
||||
public static final int CHECK_STEP_SIGN_IN = 2;
|
||||
public static final int CHECK_STEP_CRASH = 2;
|
||||
public static final int CHECK_STEP_SIGN_IN = 3;
|
||||
|
||||
public static final String KEY_TARGET_SCENE = "target_scene";
|
||||
public static final String KEY_TARGET_ARGS = "target_args";
|
||||
@@ -97,6 +100,7 @@ public final class MainActivity extends StageActivity
|
||||
static {
|
||||
registerLaunchMode(WarningScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(AnalyticsScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(CrashScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(SignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(WebViewSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
registerLaunchMode(CookieSignInScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK);
|
||||
@@ -121,6 +125,11 @@ public final class MainActivity extends StageActivity
|
||||
break;
|
||||
}
|
||||
case CHECK_STEP_ANALYTICS:
|
||||
if (Crash.hasCrashFile()) {
|
||||
startScene(new Announcer(CrashScene.class).setArgs(args));
|
||||
break;
|
||||
}
|
||||
case CHECK_STEP_CRASH:
|
||||
if (!EhUtils.hasSignedIn(this)) {
|
||||
startScene(new Announcer(SignInScene.class).setArgs(args));
|
||||
break;
|
||||
@@ -165,6 +174,8 @@ public final class MainActivity extends StageActivity
|
||||
return new Announcer(WarningScene.class);
|
||||
} else if (Settings.getAskAnalytics()) {
|
||||
return new Announcer(AnalyticsScene.class);
|
||||
} else if (Crash.hasCrashFile()) {
|
||||
return new Announcer(CrashScene.class);
|
||||
} else if (!EhUtils.hasSignedIn(this)) {
|
||||
return new Announcer(SignInScene.class);
|
||||
} else {
|
||||
@@ -187,6 +198,11 @@ public final class MainActivity extends StageActivity
|
||||
newArgs.putString(KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
newArgs.putBundle(KEY_TARGET_ARGS, announcer.getArgs());
|
||||
return new Announcer(AnalyticsScene.class).setArgs(newArgs);
|
||||
} else if (Crash.hasCrashFile()) {
|
||||
Bundle newArgs = new Bundle();
|
||||
newArgs.putString(KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
newArgs.putBundle(KEY_TARGET_ARGS, announcer.getArgs());
|
||||
return new Announcer(CrashScene.class).setArgs(newArgs);
|
||||
} else if (!EhUtils.hasSignedIn(this)) {
|
||||
Bundle newArgs = new Bundle();
|
||||
newArgs.putString(KEY_TARGET_SCENE, announcer.getClazz().getName());
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.preference.PreferenceFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import com.hippo.ehviewer.Analytics;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.UrlOpener;
|
||||
@@ -83,7 +84,7 @@ public class AboutFragment extends PreferenceFragment
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
String key = preference.getKey();
|
||||
if (KEY_AUTHOR.equals(key)) {
|
||||
ActivityHelper.sendEmail(getActivity(), "ehviewersu$gmail.com".replace('$', '@'),
|
||||
ActivityHelper.sendEmail(getActivity(), EhApplication.getDeveloperEmail(),
|
||||
"About EhViewer", null);
|
||||
} else if (KEY_GOOGLE_PLUS.equals(key)) {
|
||||
UrlOpener.openUrl(getActivity(), "https://plus.google.com/communities/103823982034655188459",
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.ui.scene;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hippo.ehviewer.Crash;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
public class CrashScene extends BaseScene implements View.OnClickListener {
|
||||
|
||||
/*---------------
|
||||
Whole life cycle
|
||||
---------------*/
|
||||
@Nullable
|
||||
private String mCrash;
|
||||
|
||||
/*---------------
|
||||
View life cycle
|
||||
---------------*/
|
||||
@Nullable
|
||||
private View mCancel;
|
||||
@Nullable
|
||||
private View mSend;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mCrash = Crash.getCrashContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
mCrash = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_crash, container, false);
|
||||
|
||||
mCancel = ViewUtils.$$(view, R.id.cancel);
|
||||
mSend = ViewUtils.$$(view, R.id.send);
|
||||
|
||||
mCancel.setOnClickListener(this);
|
||||
mSend.setOnClickListener(this);
|
||||
|
||||
RippleSalon.addRipple(mCancel, true);
|
||||
RippleSalon.addRipple(mSend, true);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mSend == v && null != mCrash) {
|
||||
ActivityHelper.sendEmail(getActivity(), EhApplication.getDeveloperEmail(),
|
||||
"I found a bug in EhViewer !", mCrash);
|
||||
}
|
||||
Crash.resetCrashFile();
|
||||
|
||||
// Start new scene and finish it self
|
||||
((MainActivity) getActivity()).startSceneForCheckStep(
|
||||
MainActivity.CHECK_STEP_CRASH, getArguments());
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public final class PackageUtils {
|
||||
|
||||
private static final String TAG = PackageUtils.class.getSimpleName();
|
||||
|
||||
public static String getSignature(Context context, String packageName) {
|
||||
try {
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||
Signature[] ss = pi.signatures;
|
||||
if (ss != null && ss.length >= 1) {
|
||||
return computeSHA1(ss[0].toByteArray());
|
||||
} else {
|
||||
Log.e(TAG, "Can't find signature in package " + packageName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't find package " + packageName, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return looks like A1:43:6B:34... or null
|
||||
*/
|
||||
public static String computeSHA1(final byte[] certRaw) {
|
||||
StringBuilder sb = new StringBuilder(59);
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
byte[] sha1 = md.digest(certRaw);
|
||||
int length = sha1.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(':');
|
||||
}
|
||||
byte b = sha1[i];
|
||||
String appendStr = Integer.toString(b & 0xff, 16);
|
||||
if (appendStr.length() == 1) {
|
||||
sb.append(0);
|
||||
}
|
||||
sb.append(appendStr);
|
||||
}
|
||||
|
||||
return sb.toString().toUpperCase();
|
||||
}
|
||||
catch (NoSuchAlgorithmException ex) {
|
||||
Log.e(TAG, "Can't final Algorithm SHA1", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user