package com.ittianyu.mobileguard.activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Environment;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.ittianyu.mobileguard.BuildConfig;
import com.ittianyu.mobileguard.R;
import com.ittianyu.mobileguard.activity.base.BaseActivityFullScreen;
import com.ittianyu.mobileguard.constant.Constant;
import com.ittianyu.mobileguard.domain.VersionBean;
import com.ittianyu.mobileguard.utils.ProgressDownloadUtils;
import com.ittianyu.mobileguard.utils.ProgressResponseBody;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* start activity
*/
public class SplashActivity extends BaseActivityFullScreen {
// constants
private static final String VERSION_URL = "http://10.0.2.2/mobileguardversion.json";
private static final String NEW_VERSION_APK = "MobileGuardNew.apk";
// animation time
private static final int ANIMATION_DURATION = 700;
// show time
private static final int LOGO_SHOW_TIME = 500;
// result code
private static final int REQUEST_CODE_INSTALL_NEW_VERSION = 1;
private static final int TIMEOUT = 3;
// data
private OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.build();
private boolean autoUpdate;
/**
* changet init order
*/
@Override
protected void init() {
initData();
initView();
initEvent();
}
/**
* 1
*/
@Override
protected void initData() {
// get auto update cinfig
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
autoUpdate = sp.getBoolean(Constant.KEY_CB_AUTO_UPDATE, true);
// System.out.println("autoUpdate:" + autoUpdate);
}
/**
* 2
*/
@Override
protected void initView() {
setContentView(R.layout.activity_splash);
// set animation
setAnimation();
// get local version
// getAppVersionInfo();// now replace by the word on image
// auto update check
if(autoUpdate) {
// get latest version info
getVersionInfo();
}// if not update, it will start main activity on animation end
}
/**
* 3
*/
@Override
protected void initEvent() {
}
/**
* check version.
* Need run on UI thread
* Showing a dialog to query user whether to update app, if local version code < latest version code
*
* @param latestVersionInfo the latest version bean
*/
private void checkVersion(final VersionBean latestVersionInfo) {
if (null == latestVersionInfo || BuildConfig.VERSION_CODE >= latestVersionInfo.getVersion()) {
startMainActivity();
return;
}
// show dialog to query whether to update
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.update_tips)
.setMessage(getString(R.string.update_description) + latestVersionInfo.getDescription())
// .setCancelable(false)// can't be canceled by esc or touch other position
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
startMainActivity();
}
})
.setPositiveButton(R.string.update, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateApp(latestVersionInfo.getUrl());
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startMainActivity();
}
})
.create();
dialog.show();
}
/**
* download the new apk and install
*
* @param url
*/
private void updateApp(final String url) {
// download apk, the install will be started after download success
downloadNewVersion(url);
}
/**
* 安装新版本
*
* @param file the apk
*/
private void installNewVersion(final File file) throws FileNotFoundException {
/*
<activity android:name=".PackageInstallerActivity"
android:configChanges="orientation|keyboardHidden"
android:theme="@style/TallTitleBarTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
*/
if (null == file)
throw new NullPointerException("file can't be null");
if (!file.exists())
throw new FileNotFoundException("file " + file.getAbsolutePath() + " can't be found");
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivityForResult(intent, REQUEST_CODE_INSTALL_NEW_VERSION);
}
/**
* on the started activity return result
* will start the main activity
*
* @param requestCode request code
* @param resultCode result code
* @param data data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_CODE_INSTALL_NEW_VERSION:
startMainActivity();
break;
}
}
/**
* download the new apk
*
* @param url the url of new version
*/
private void downloadNewVersion(final String url) {
/* Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SplashActivity.this, R.string.failed_to_download, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream in = response.body().byteStream();
FileUtils.saveFileWithStream(new File(Environment.getExternalStorageDirectory(), NEW_VERSION_APK), in);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SplashActivity.this, R.string.success_to_download, Toast.LENGTH_SHORT).show();
// install apk
try {
installNewVersion(new File(Environment.getExternalStorageDirectory(), NEW_VERSION_APK));
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(SplashActivity.this, R.string.failed_to_install_new_version, Toast.LENGTH_SHORT).show();
}
}
});
}
});*/
// show progress dialog
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setTitle(R.string.download);
progressDialog.setMessage(getString(R.string.download_tips));
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
startMainActivity();
}
});
progressDialog.setIndeterminate(false);// show progress bar
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setProgress(0);
progressDialog.show();
// download
ProgressDownloadUtils downloadUtils = new ProgressDownloadUtils(url, new File(Environment.getExternalStorageDirectory(), NEW_VERSION_APK), new ProgressResponseBody.ProgressListener() {
@Override
public void onPreExecute(long contentLength) {
// set the max, change contentLength from b to kb
progressDialog.setMax((int) (contentLength / 1024));
}
@Override
public void update(long totalBytes, boolean done) {
// set the progress, change contentLength from b to kb
progressDialog.setProgress((int) (totalBytes / 1024));
// download success
if (done) {
runOnUiThread(new Runnable() {
@Override
public void run() {
progressDialog.cancel();// if not call, will cause "Activity has leaked window"
Toast.makeText(SplashActivity.this, R.string.success_to_download, Toast.LENGTH_SHORT).show();
// install apk
try {
installNewVersion(new File(Environment.getExternalStorageDirectory(), NEW_VERSION_APK));
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(SplashActivity.this, R.string.failed_to_install_new_version, Toast.LENGTH_SHORT).show();
}
}
});
}
}
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SplashActivity.this, R.string.failed_to_download, Toast.LENGTH_SHORT).show();
startMainActivity();
}
});
}
});
downloadUtils.download(0L);
}
/**
* start the main activity
*/
private void startMainActivity() {
startActivity(new Intent(this, MainActivity.class));
finish();
}
/**
* get the version info in gradle and set to TextView
*/
private void getAppVersionInfo() {
// TextView tvVersionName = (TextView) findViewById(R.id.tv_splash_version_name);
// tvVersionName.setText(BuildConfig.VERSION_NAME);
}
/**
* get latest version info
* the result will show at least ANIMATION_DURATION millisecond.
* It means that the result will be show until animation finish
*/
private void getVersionInfo() {
// get the start time
final long startTime = System.currentTimeMillis();
// send request
Request request = new Request.Builder().get()
.url(VERSION_URL)
.build();
client.newCall(request).enqueue(new Callback() {
// failed
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SplashActivity.this, R.string.failed_to_connect_internet, Toast.LENGTH_SHORT).show();
}
});
// wait for animation and check version
waitForAnimationFinishAndCheckVersion(startTime, null);
}
// parse json
@Override
public void onResponse(Call call, Response response) throws IOException {
String jsonString = response.body().string();
System.out.println(jsonString);
Gson gson = new Gson();
VersionBean latestVersionInfo = null;
try {
latestVersionInfo = gson.fromJson(jsonString, VersionBean.class);
} catch (JsonSyntaxException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(SplashActivity.this, R.string.json_parse_error, Toast.LENGTH_SHORT).show();
}
});
}
System.out.println(latestVersionInfo);
// wait for animation and check version
waitForAnimationFinishAndCheckVersion(startTime, latestVersionInfo);
}
});
}
/**
* wait for animation finish.
* Need run on child thread
* and check version will run on ui thread
*
* @param startTime the time at the begin of getVersionInfo
* @param latestVersionInfo the latest version bean
*/
private void waitForAnimationFinishAndCheckVersion(final long startTime, final VersionBean latestVersionInfo) {
// wait for animation finish
long endTime = System.currentTimeMillis();
long interval = ANIMATION_DURATION + LOGO_SHOW_TIME - (endTime - startTime);
if (interval > 0) {
SystemClock.sleep(interval);
}
// check version
runOnUiThread(new Runnable() {
@Override
public void run() {
checkVersion(latestVersionInfo);
}
});
}
/**
* set animation
* alpha freom 0 to 1 in 3s
*/
private void setAnimation() {
// alpha
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(ANIMATION_DURATION);
// alphaAnimation.setFillAfter(true);
// rotate
RotateAnimation rotateAnimation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(ANIMATION_DURATION);
// rotateAnimation.setFillAfter(true);
// scale
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(ANIMATION_DURATION);
// scaleAnimation.setFillAfter(true);
// animation set
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
// set animation listener
// when animation finish, start main activity if autoUpdate equal false
if(!autoUpdate) {
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
System.out.println("onAnimationEnd:startMainActivity");
// wait for LOGO_SHOW_TIME then start main activity
new Thread(){
@Override
public void run() {
SystemClock.sleep(LOGO_SHOW_TIME);
runOnUiThread(new Runnable() {
@Override
public void run() {
startMainActivity();
}
});
}
}.start();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
// get root view of activity
View vRoot = findViewById(R.id.activity_splash);
// start animation
vRoot.startAnimation(animationSet);
}
}