Skip to content

Commit

Permalink
Ver.2.5.2 (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
s1204IT authored Feb 14, 2025
1 parent 22be211 commit 55fc6d5
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 12 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
minSdk = 22
//noinspection ExpiredTargetSdkVersion
targetSdk = 22
versionCode = 58
versionName = "2.5.1"
versionCode = 59
versionName = "2.5.2"
proguardFiles += "proguard-rules.pro"
multiDexEnabled = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import android.widget.TextView;

import com.saradabar.cpadcustomizetool.data.task.ApkMCopyTask;
import com.saradabar.cpadcustomizetool.data.task.ApkSCopyTask;
import com.saradabar.cpadcustomizetool.data.task.XApkCopyTask;

public class ByteProgressHandler extends Handler {

public XApkCopyTask xApkCopyTask;
public ApkMCopyTask apkMCopyTask;
public ApkSCopyTask apkSCopyTask;
public ProgressBar progressBar;
public TextView textPercent, textByte;

Expand Down Expand Up @@ -65,5 +67,18 @@ public void handleMessage(@NonNull Message msg) {

sendEmptyMessageDelayed(0, 100);
}

if (apkSCopyTask != null) {
if (apkSCopyTask.isFinish()) {
progressBar.setProgress(0);
return;
}

progressBar.setProgress(apkSCopyTask.getLoadedBytePercent(progressBar.getContext()));
textPercent.setText(new StringBuilder(String.valueOf(progressBar.getProgress())).append("%"));
textByte.setText(new StringBuilder(String.valueOf(apkSCopyTask.getLoadedCurrentByte(textByte.getContext()))).append(" / ").append(apkSCopyTask.getLoadedTotalByte()).append(" MB"));

sendEmptyMessageDelayed(0, 100);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package com.saradabar.cpadcustomizetool.data.task;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;

import com.saradabar.cpadcustomizetool.R;
import com.saradabar.cpadcustomizetool.util.Common;

import org.zeroturnaround.zip.ZipUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.Executors;

public class ApkSCopyTask {

long totalByte = 0;

public void execute(Context context, Listener listener, ArrayList<String> splitInstallData) {
onPreExecute(listener);
Executors.newSingleThreadExecutor().submit(() -> {
Handler handler = new Handler(Looper.getMainLooper());
new Thread(() -> {
Object result = doInBackground(context, listener, splitInstallData);
handler.post(() -> onPostExecute(context, listener, result));
}).start();
});
}

void onPreExecute(Listener listener) {
listener.onShow();
}

void onPostExecute(Context context, Listener listener, Object result) {
if (result == null) {
totalByte = -1;
listener.onError(context.getString(R.string.installer_status_unknown_error));
return;
}

if (result.getClass() == ArrayList.class) {
ArrayList<String> stringArrayList = new ArrayList<>();

for (Object o : (Iterable<?>) result) {
stringArrayList.add((String) o);
}

totalByte = -1;
listener.onSuccess(stringArrayList);
return;
}

if (result.equals(false)) {
totalByte = -1;
listener.onFailure();
return;
}

totalByte = -1;
listener.onError(result.toString());
}

public void onProgressUpdate(Listener listener, String message) {
listener.onProgressUpdate(message);
}

protected Object doInBackground(Context context, Listener listener, ArrayList<String> splitInstallData) {
//noinspection SequencedCollectionMethodCanBeUsed
String zipFile = splitInstallData.get(0);
File tmpFile = new File(Common.getTemporaryPath(context));
totalByte = new File(zipFile).length();

// apksのファイルパスを削除
//noinspection SequencedCollectionMethodCanBeUsed
splitInstallData.remove(0);

/* zipを展開して外部ディレクトリに一時保存 */
onProgressUpdate(listener, context.getString(R.string.progress_state_unpack));

try {
ZipUtil.unpack(new File(zipFile), tmpFile);
// .apks を展開した splits の中が .apk 群
tmpFile = new File(Common.getTemporaryPath(context) + "/splits");
} catch (Exception e) {
return e.getMessage();
}

File[] zipListFiles = tmpFile.listFiles();

if (zipListFiles != null) {
int c = 0;

/* ディレクトリのなかのファイルを取得 */
for (int i = 0; i < zipListFiles.length; i++) {
if (zipListFiles[i].isDirectory()) {
c++;
} else {
onProgressUpdate(listener, context.getString(R.string.progress_state_check_file));
zipFile = zipListFiles[i].getName();

/* apkファイルならパスをインストールデータへ */
if (zipFile.substring(zipFile.lastIndexOf(".")).equalsIgnoreCase(".apk")
&& !zipFile.endsWith("master_2.apk")) {
splitInstallData.add(i - c, zipListFiles[i].getPath());
} else {
/* apkファイルでなかったときのリストの順番を修正 */
c++;
}
}
}
return splitInstallData;
} else {
return false;
}
}

public interface Listener {
void onShow();

void onSuccess(ArrayList<String> splitInstallData);

void onFailure();

void onError(String message);

void onProgressUpdate(String message);
}

public int getLoadedBytePercent(Context context) {
if (totalByte <= 0) {
return 0;
}
return (int) Math.floor(((double) getLoadedCurrentByte(context) / getLoadedTotalByte()) * 100);
}

public int getLoadedTotalByte() {
return (int) totalByte / (1024 * 1024);
}

@TargetApi(Build.VERSION_CODES.O)
public int getLoadedCurrentByte(Context context) {
if (totalByte <= 0) {
return 0;
}
return (int) Common.getFileSize(new File(Common.getTemporaryPath(context))) / (1024 * 1024);
}

public boolean isFinish() {
return totalByte == -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private void initialize() {

text1.setText(new StringBuilder("アプリ名:").append(getApplicationInfo().loadLabel(getPackageManager())));
text2.setText(new StringBuilder("パッケージ名:").append(BuildConfig.APPLICATION_ID));
text3.setText(new StringBuilder("バージョン:").append(BuildConfig.VERSION_NAME));
text3.setText(new StringBuilder("バージョン:Ver.").append(BuildConfig.VERSION_NAME));
text4.setText(new StringBuilder("バージョンコード:").append(BuildConfig.VERSION_CODE));
text5.setText(getString(R.string.info_app_state, BuildConfig.BUILD_TYPE));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.saradabar.cpadcustomizetool.data.service.DhizukuService;
import com.saradabar.cpadcustomizetool.data.service.IDhizukuService;
import com.saradabar.cpadcustomizetool.data.task.ApkInstallTask;
import com.saradabar.cpadcustomizetool.data.task.ApkSCopyTask;
import com.saradabar.cpadcustomizetool.data.task.ApkMCopyTask;
import com.saradabar.cpadcustomizetool.data.task.IDhizukuTask;
import com.saradabar.cpadcustomizetool.data.task.XApkCopyTask;
Expand All @@ -67,6 +68,7 @@ public class DeviceOwnerFragment extends PreferenceFragmentCompat implements Ins

XApkCopyTask xApkCopyTask;
ApkMCopyTask apkMCopyTask;
ApkSCopyTask apkSCopyTask;

public Preference preUninstallBlock,
preSessionInstall,
Expand Down Expand Up @@ -422,6 +424,9 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
} else if (installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apkm")) {
apkMCopyTask = new ApkMCopyTask();
apkMCopyTask.execute(requireActivity(), apkMListener(), installFileArrayList);
} else if (installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apks")) {
apkSCopyTask = new ApkSCopyTask();
apkSCopyTask.execute(requireActivity(), apkSListener(), installFileArrayList);
}
} else {
new AlertDialog.Builder(requireActivity())
Expand Down Expand Up @@ -455,7 +460,10 @@ private boolean trySetInstallData(Intent intent, ArrayList<String> stringArrayLi

/* ファイルの拡張子 */
/* 未対応またはインストールファイルでないなら終了 */
return installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apk") || installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".xapk") || installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apkm");
return installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apk")
|| installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".xapk")
|| installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apkm")
|| installFileName.substring(installFileName.lastIndexOf(".")).equalsIgnoreCase(".apks");
} else {
/* マルチApk */
for (int i = 0; i < clipData.getItemCount(); i++) {
Expand Down Expand Up @@ -725,6 +733,95 @@ public void onProgressUpdate(String message) {
};
}

public ApkSCopyTask.Listener apkSListener() {
return new ApkSCopyTask.Listener() {

AlertDialog alertDialog;
ByteProgressHandler progressHandler;

@Override
public void onShow() {
View view = getLayoutInflater().inflate(R.layout.view_progress, null);
ProgressBar progressBar = view.findViewById(R.id.progress);
TextView textPercent = view.findViewById(R.id.progress_percent);
TextView textByte = view.findViewById(R.id.progress_byte);

progressBar.setProgress(0);
textPercent.setText(new StringBuilder(progressBar.getProgress()).append(getString(R.string.percent)));

alertDialog = new AlertDialog.Builder(DeviceOwnerFragment.this.requireActivity())
.setView(view)
.setMessage("")
.setCancelable(false)
.create();

if (!alertDialog.isShowing()) {
alertDialog.show();
}

progressHandler = new ByteProgressHandler(Looper.getMainLooper());
progressHandler.progressBar = progressBar;
progressHandler.textPercent = textPercent;
progressHandler.textByte = textByte;
progressHandler.apkMCopyTask = apkMCopyTask;
progressHandler.sendEmptyMessage(0);
}

@Override
public void onSuccess(ArrayList<String> stringArrayList) {
alertDialog.dismiss();
new ApkInstallTask().execute(requireActivity(), apkInstallTaskListener(), stringArrayList, Constants.REQUEST_INSTALL_SILENT, DeviceOwnerFragment.this);
}

@Override
public void onFailure() {
alertDialog.dismiss();
try {
/* 一時ファイルを消去 */
File tmpFile = requireActivity().getExternalCacheDir();

if (tmpFile != null) {
FileUtils.deleteDirectory(tmpFile);
}
} catch (IOException ignored) {
}

new AlertDialog.Builder(DeviceOwnerFragment.this.requireActivity())
.setTitle(getString(R.string.dialog_title_error))
.setMessage(getString(R.string.dialog_failure))
.setCancelable(false)
.setPositiveButton(R.string.dialog_common_ok, null)
.show();
}

@Override
public void onError(String message) {
alertDialog.dismiss();
try {
/* 一時ファイルを消去 */
File tmpFile = requireActivity().getExternalCacheDir();

if (tmpFile != null) {
FileUtils.deleteDirectory(tmpFile);
}
} catch (IOException ignored) {
}

new AlertDialog.Builder(DeviceOwnerFragment.this.requireActivity())
.setTitle(getString(R.string.dialog_title_error))
.setMessage(message)
.setCancelable(false)
.setPositiveButton(R.string.dialog_common_ok, null)
.show();
}

@Override
public void onProgressUpdate(String message) {
alertDialog.setMessage(message);
}
};
}

@Override
public void onInstallSuccess(int reqCode) {
if (reqCode == Constants.REQUEST_INSTALL_SILENT) {
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@
<string name="pre_main_sum_change_to_normal_mode_settings">デフォルトはすべて変更されます。</string>
<string name="pre_main_sum_use_dcha">有効にするには、タップしてください。</string>
<string name="pre_main_sum_device_admin">このアプリがアンインストールされないようにします。</string>
<string name="pre_main_sum_silent_install">apk のインストールに対応しています。 split apk は、デバイスオーナーの機能 -> サイレントインストールからインストールできます。</string>
<string name="pre_main_sum_silent_install">単一APK のインストールに対応しています。\n分割APK は [デバイスオーナーの機能] -> [サイレントインストール] からインストールできます。</string>
<string name="pre_main_sum_already_device_owner">デバイスオーナーのため変更できません。</string>
<string name="pre_main_sum_no_setting_launcher">ホームは設定されていません。</string>
<string name="pre_main_sum_get_app">表示されるダイアログからアプリを選択してください。インストーラーは、アプリ設定 -> インストールモードから変更できます。</string>
<string name="pre_main_sum_get_app">表示されるダイアログからアプリを選択してください。インストーラーは、[アプリ設定] -> [インストールモード] から変更できます。</string>

<!-- アプリ設定 -->
<string name="pre_app_category_start_settings">起動設定</string>
Expand All @@ -100,11 +100,11 @@
<string name="pre_owner_title_permission">ランタイム権限の強制付与</string>
<string name="pre_owner_title_silent_install">サイレントインストール</string>
<string name="pre_owner_title_device_owner">デバイスオーナーの解除</string>
<string name="pre_owner_sum_message_1">デバイスオーナーは %1$s に設定されています。</string>
<string name="pre_owner_sum_message_1">デバイスオーナーは <b>%1$s</b> に設定されています。</string>
<string name="pre_owner_sum_no_device_owner">デバイスオーナーは設定されていません。</string>
<string name="pre_owner_sum_not_use_function">デバイスオーナーが設定されていないため、この機能は使用できません。</string>
<string name="pre_owner_sum_uninstall_block">ユーザーアプリのアンインストールをブロックします。</string>
<string name="pre_owner_sum_silent_install">apk, xapk, apkm, split apk をインストールできます。 split apk のインストールは、ファイルを長押しして選択してください。</string>
<string name="pre_owner_sum_silent_install">単一APK 及び 分割APK(xapk, apkm, apks) をインストールできます。\n分割APK のインストールは、ファイルを<b>長押し</b>して選択してください。</string>
<string name="pre_owner_sum_permission_forced">デバイスポリシーでユーザーアプリのランタイム権限は強制付与されます。</string>
<string name="pre_owner_sum_permission_default">デバイスポリシーはデフォルトです。</string>

Expand Down Expand Up @@ -156,7 +156,7 @@
<string name="dialog_question_admin">この操作を行うと学習環境のときに、アプリがアンインストールされる可能性があります。</string>

<!-- ダイアログエラー -->
<string name="dialog_error_crash">致命的なエラーが発生しました。 OK を押すと、メイン画面に戻ります。\n\n繰り返し発生する場合は 報告 を押してクラッシュログを開発者に報告できます。クラッシュログは 報告 を押すと自動でコピーされますので、表示されるフォームの入力欄に貼り付けてください。\n報告手順\n・「問題のカテゴリを選択してください。」でバグレポートを選択して「次へ」を押します。\n・最新バージョンであれば「はい」を押して「次へ」を押します。\n・「どのような問題が発生しますか?」の入力欄で長押ししてペーストを押します。\n\nクラッシュログを確認、またはコピーしたいときは 確認 を押してください。</string>
<string name="dialog_error_crash">致命的なエラーが発生しました。\nOK を押すと、メイン画面に戻ります。\n\n繰り返し発生する場合は [報告] を押してクラッシュログを開発者に報告できます。クラッシュログは [報告] を押すと自動でコピーされますので、表示されるフォームの入力欄に貼り付けてください。\n報告手順\n・「問題のカテゴリを選択してください。」でバグレポートを選択して「次へ」を押します。\n・最新バージョンであれば「はい」を押して「次へ」を押します。\n・「どのような問題が発生しますか?」の入力欄で長押ししてペーストを押します。\n\nクラッシュログを確認、またはコピーしたいときは 確認 を押してください。</string>
<string name="dialog_error">エラーが発生しました。</string>
<string name="dialog_error_connection">"データ取得に失敗しました。ネットワークを確認してください。"</string>
<string name="dialog_error_download">"ダウンロードに失敗しました。ネットワークを確認してください。"</string>
Expand Down Expand Up @@ -231,7 +231,7 @@
<!-- インストーラー -->
<string name="installer_status_user_action">ユーザの確認が必要です。</string>
<string name="installer_status_failure_storage">ストレージの空き領域が不足しています。</string>
<string name="installer_status_failure_invalid">apk が無効か破損しています。</string>
<string name="installer_status_failure_invalid">APK ファイルが無効か破損しています。</string>
<string name="installer_status_failure_incompatible">非対応アプリです。</string>
<string name="installer_status_failure_conflict">衝突するアプリが存在します。</string>
<string name="installer_status_failure_blocked">インストールがブロックされました。</string>
Expand Down
Loading

0 comments on commit 55fc6d5

Please sign in to comment.