Add saving logs feature for installation

This commit is contained in:
topjohnwu 2017-11-18 03:55:47 +08:00
parent 49c672ac4d
commit 3a74729ecc
31 changed files with 154 additions and 112 deletions

View File

@ -11,6 +11,7 @@ import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.InstallMagisk;
@ -19,6 +20,14 @@ import com.topjohnwu.magisk.container.CallbackList;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Shell;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
@ -27,32 +36,50 @@ public class FlashActivity extends Activity {
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.txtLog) TextView flashLogs;
@BindView(R.id.button_panel) LinearLayout buttonPanel;
@BindView(R.id.reboot) Button reboot;
@BindView(R.id.button_panel) public LinearLayout buttonPanel;
@BindView(R.id.reboot) public Button reboot;
@BindView(R.id.scrollView) ScrollView sv;
private List<String> logs;
@OnClick(R.id.no_thanks)
public void dismiss() {
void dismiss() {
finish();
}
@OnClick(R.id.reboot)
public void reboot() {
void reboot() {
Shell.su_raw("reboot");
}
@OnClick(R.id.save_logs)
void saveLogs() {
Calendar now = Calendar.getInstance();
String filename = String.format(Locale.US,
"install_log_%04d%02d%02d_%02d:%02d:%02d.log",
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
File logFile = new File(Const.EXTERNAL_PATH + "/logs", filename);
logFile.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(logFile)) {
for (String s : logs) {
writer.write(s);
writer.write('\n');
}
} catch (IOException e) {
e.printStackTrace();
return;
}
MagiskManager.toast(logFile.getPath(), Toast.LENGTH_LONG);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flash);
ButterKnife.bind(this);
CallbackList<String> rootShellOutput = new CallbackList<String>() {
@Override
public synchronized void onAddElement() {
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
}
};
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
if (ab != null) {
@ -63,6 +90,16 @@ public class FlashActivity extends Activity {
if (!Shell.rootAccess())
reboot.setVisibility(View.GONE);
logs = new ArrayList<>();
List<String> console = new CallbackList<String>() {
@Override
public synchronized void onAddElement(String e) {
logs.add(e);
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
}
};
// We must receive a Uri of the target zip
Intent intent = getIntent();
Uri uri = intent.getData();
@ -70,35 +107,17 @@ public class FlashActivity extends Activity {
boolean keepEnc = intent.getBooleanExtra(Const.Key.FLASH_SET_ENC, false);
boolean keepVerity = intent.getBooleanExtra(Const.Key.FLASH_SET_VERITY, false);
switch (getIntent().getStringExtra(Const.Key.FLASH_ACTION)) {
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
case Const.Value.FLASH_ZIP:
new FlashZip(this, uri, rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
new FlashZip(this, uri, console, logs).exec();
break;
case Const.Value.PATCH_BOOT:
new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT))
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, (Uri) intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT))
.exec();
break;
case Const.Value.FLASH_MAGISK:
String boot = intent.getStringExtra(Const.Key.FLASH_SET_BOOT);
if (getMagiskManager().remoteMagiskVersionCode < 1370) {
// Use legacy installation method
Shell.su_raw(
"echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk",
"echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk"
);
new FlashZip(this, uri, rootShellOutput)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
} else {
// Use new installation method
new InstallMagisk(this, rootShellOutput, uri, keepEnc, keepVerity, boot)
.setCallBack(() -> buttonPanel.setVisibility(View.VISIBLE))
.exec();
}
new InstallMagisk(this, console, logs, uri, keepEnc, keepVerity, intent.getStringExtra(Const.Key.FLASH_SET_BOOT))
.exec();
break;
}
}

View File

@ -1,7 +1,6 @@
package com.topjohnwu.magisk;
import android.Manifest;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;

View File

@ -3,9 +3,10 @@ package com.topjohnwu.magisk.asyncs;
import android.app.Activity;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
@ -25,12 +26,13 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
private Uri mUri;
private File mCachedFile;
private List<String> mList;
private List<String> console, logs;
public FlashZip(Activity context, Uri uri, List<String> list) {
public FlashZip(Activity context, Uri uri, List<String> console, List<String> logs) {
super(context);
mUri = uri;
mList = list;
this.console = console;
this.logs = logs;
mCachedFile = new File(context.getCacheDir(), "install.zip");
}
@ -44,7 +46,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
protected Integer doInBackground(Void... voids) {
MagiskManager mm = MagiskManager.get();
try {
mList.add("- Copying zip to temp directory");
console.add("- Copying zip to temp directory");
mCachedFile.delete();
try (
@ -55,48 +57,52 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
InputStream buf= new BufferedInputStream(in);
Utils.inToOut(buf, out);
} catch (FileNotFoundException e) {
mList.add("! Invalid Uri");
console.add("! Invalid Uri");
throw e;
} catch (IOException e) {
mList.add("! Cannot copy to cache");
console.add("! Cannot copy to cache");
throw e;
}
if (!unzipAndCheck()) return 0;
mList.add("- Installing " + Utils.getNameFromUri(mm, mUri));
Shell.su(mList,
console.add("- Installing " + Utils.getNameFromUri(mm, mUri));
Shell.getShell().run(console, logs,
"cd " + mCachedFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile +
" && echo 'Success!' || echo 'Failed!'"
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + " || echo 'Failed!'"
);
if (TextUtils.equals(mList.get(mList.size() - 1), "Success!"))
return 1;
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return -1;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
return -1;
console.add("- All done!");
return 1;
}
// -1 = error, manual install; 0 = invalid zip; 1 = success
@Override
protected void onPostExecute(Integer result) {
MagiskManager mm = MagiskManager.get();
FlashActivity activity = (FlashActivity) getActivity();
Shell.su_raw(
"rm -rf " + mCachedFile.getParent(),
"rm -rf " + Const.TMP_FOLDER_PATH
);
switch (result) {
case -1:
mList.add(mm.getString(R.string.install_error));
console.add("! Installation failed");
Utils.showUriSnack(getActivity(), mUri);
break;
case 0:
mList.add(mm.getString(R.string.invalid_zip));
console.add("! This zip is not a Magisk Module!");
break;
case 1:
// Success
new LoadModules().exec();
break;
}
super.onPostExecute(result);
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
activity.buttonPanel.setVisibility(View.VISIBLE);
}
}

View File

@ -5,8 +5,10 @@ import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.view.View;
import com.topjohnwu.crypto.SignBoot;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.container.TarEntry;
import com.topjohnwu.magisk.utils.Const;
@ -35,27 +37,28 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
private static final int DIRECT_MODE = 1;
private Uri mBootImg, mZip;
private List<String> mList;
private List<String> console, logs;
private String mBootLocation;
private boolean mKeepEnc, mKeepVerity;
private int mode;
private InstallMagisk(Activity context, List<String> list, Uri zip, boolean enc, boolean verity) {
private InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, boolean enc, boolean verity) {
super(context);
mList = list;
this.console = console;
this.logs = logs;
mZip = zip;
mKeepEnc = enc;
mKeepVerity = verity;
}
public InstallMagisk(Activity context, List<String> list, Uri zip, boolean enc, boolean verity, Uri boot) {
this(context, list, zip, enc, verity);
public InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, boolean enc, boolean verity, Uri boot) {
this(context, console, logs, zip, enc, verity);
mBootImg = boot;
mode = PATCH_MODE;
}
public InstallMagisk(Activity context, List<String> list, Uri zip, boolean enc, boolean verity, String boot) {
this(context, list, zip, enc, verity);
public InstallMagisk(Activity context, List<String> console, List<String> logs, Uri zip, boolean enc, boolean verity, String boot) {
this(context, console, logs, zip, enc, verity);
mBootLocation = boot;
mode = DIRECT_MODE;
}
@ -77,11 +80,11 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
else if (abis.contains("arm64-v8a")) arch = "arm64";
else if (abis.contains("x86")) arch = "x86";
else arch = "arm";
mList.add("- Device platform: " + arch);
console.add("- Device platform: " + arch);
try {
// Unzip files
mList.add("- Extracting files");
console.add("- Extracting files");
try (InputStream in = mm.getContentResolver().openInputStream(mZip)) {
if (in == null) throw new FileNotFoundException();
BufferedInputStream buf = new BufferedInputStream(in);
@ -95,17 +98,17 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
ZipUtils.unzip(buf, install, "META-INF/com/google/android/update-binary", true);
buf.close();
} catch (FileNotFoundException e) {
mList.add("! Invalid Uri");
console.add("! Invalid Uri");
throw e;
} catch (Exception e) {
mList.add("! Cannot unzip zip");
console.add("! Cannot unzip zip");
throw e;
}
File boot = new File(install, "boot.img");
switch (mode) {
case PATCH_MODE:
mList.add("- Use boot image: " + boot);
console.add("- Use boot image: " + boot);
// Copy boot image to local
try (
InputStream in = mm.getContentResolver().openInputStream(mBootImg);
@ -129,19 +132,19 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
}
Utils.inToOut(source, out);
} catch (FileNotFoundException e) {
mList.add("! Invalid Uri");
console.add("! Invalid Uri");
throw e;
} catch (IOException e) {
mList.add("! Copy failed");
console.add("! Copy failed");
throw e;
}
break;
case DIRECT_MODE:
mList.add("- Use boot image: " + mBootLocation);
console.add("- Use boot image: " + mBootLocation);
if (boot.createNewFile()) {
Shell.su("cat " + mBootLocation + " > " + boot);
} else {
mList.add("! Dump boot image failed");
console.add("! Dump boot image failed");
return false;
}
break;
@ -153,10 +156,10 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
try (InputStream in = new FileInputStream(boot)) {
isSigned = SignBoot.verifySignature(in, null);
if (isSigned) {
mList.add("- Signed boot image detected");
console.add("- Signed boot image detected");
}
} catch (Exception e) {
mList.add("! Unable to check signature");
console.add("! Unable to check signature");
throw e;
}
@ -168,12 +171,12 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
shell = Shell.getShell();
// Patch boot image
shell.run(mList, null,
shell.run(console, logs,
"cd " + install,
"KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " +
"update-binary indep boot_patch.sh " + boot + " || echo 'Failed!'");
if (TextUtils.equals(mList.get(mList.size() - 1), "Failed!"))
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return false;
shell.run(null, null,
@ -185,7 +188,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
File patched_boot = new File(install.getParent(), "new-boot.img");
if (isSigned) {
mList.add("- Signing boot image");
console.add("- Signing boot image");
File signed = new File(install.getParent(), "signed.img");
AssetManager assets = mm.getAssets();
try (
@ -217,15 +220,15 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
}
break;
}
mList.add("");
mList.add("*********************************");
mList.add(" Patched Boot Image is placed in ");
mList.add(" " + dest + " ");
mList.add("*********************************");
console.add("");
console.add("*********************************");
console.add(" Patched Boot Image is placed in ");
console.add(" " + dest + " ");
console.add("*********************************");
break;
case DIRECT_MODE:
// Direct flash boot image and patch dtbo if possible
Shell.su(mList,
Shell.getShell().run(console, logs,
"rm -rf /data/magisk/*",
"mkdir -p /data/magisk 2>/dev/null",
"mv -f " + install + "/* /data/magisk",
@ -238,7 +241,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
return false;
}
mList.add("- All done!");
console.add("- All done!");
} catch (Exception e) {
e.printStackTrace();
return false;
@ -248,6 +251,11 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
FlashActivity activity = (FlashActivity) getActivity();
if (!result) {
console.add("! Installation failed");
activity.reboot.setVisibility(View.GONE);
}
activity.buttonPanel.setVisibility(View.VISIBLE);
}
}

View File

@ -12,11 +12,11 @@ public abstract class CallbackList<E> extends ArrayList<E> {
handler = new Handler();
}
public abstract void onAddElement();
public abstract void onAddElement(E e);
public synchronized boolean add(E e) {
boolean ret = super.add(e);
handler.post(this::onAddElement);
handler.post(() -> onAddElement(e));
return ret;
}
}

View File

@ -50,6 +50,14 @@
android:layout_weight="1"
android:text="@string/close" />
<Button
android:id="@+id/save_logs"
style="?android:borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/menuSaveLog" />
<Button
android:id="@+id/reboot"
style="?android:borderlessButtonStyle"

View File

@ -5,7 +5,7 @@
<item
android:id="@+id/menu_save"
android:icon="@drawable/ic_save"
android:title="@string/menuSaveToSd"
android:title="@string/menuSaveLog"
app:showAsAction="ifRoom"/>
<item

View File

@ -53,7 +53,6 @@
<string name="not_installed">غير مثبت</string>
<!--Log Fragment-->
<string name="menuSaveToSd">حفظ إلى بطاقة ذاكرة SD</string>
<string name="menuReload">إعادة تحميل</string>
<string name="menuClearLog">حذف السجل الآن</string>
<string name="logs_cleared">تم حذف السجل بنجاح</string>

View File

@ -49,7 +49,7 @@
<string name="not_installed">Nenainstalováno</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Uložit na SD</string>
<string name="menuSaveLog">Uložit log</string>
<string name="menuReload">Aktualizovat</string>
<string name="menuClearLog">Smazat Log</string>
<string name="logs_cleared">Log byl smazán</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Nicht installiert</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Log auf SD-Karte speichern</string>
<string name="menuSaveLog">Log auf speichern</string>
<string name="menuReload">Log erneut laden</string>
<string name="menuClearLog">Log löschen</string>
<string name="logs_cleared">Log gelöscht</string>

View File

@ -52,7 +52,7 @@
<string name="not_installed">Μη εγκατεστημένη</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Αποθήκευση σε SD</string>
<string name="menuSaveLog">"Αποθήκευση καταγραφής "</string>
<string name="menuReload">Επαναφόρτωση</string>
<string name="menuClearLog">Εκκαθάριση αρχείου καταγραφής τώρα</string>
<string name="logs_cleared">Το αρχείο καταγραφής εκκαθαρίστηκε επιτυχώς</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">No Instalado</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Guardar en la SD</string>
<string name="menuSaveLog">Guardar registro</string>
<string name="menuReload">Recargar</string>
<string name="menuClearLog">Limpiar registro ahora</string>
<string name="logs_cleared">Registro limpiado correctamente</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Pole installitud</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Salvesta SD-kaardile</string>
<string name="menuSaveLog">Salvesta logi</string>
<string name="menuReload">Laadi uuesti</string>
<string name="menuClearLog">Tühjenda logi nüüd</string>
<string name="logs_cleared">Logi edukalt tühjendatud</string>

View File

@ -48,7 +48,7 @@
<string name="installed">Installé</string>
<string name="not_installed">Non installé</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Enregistrer sur SD</string>
<string name="menuSaveLog">Enregistrer journal</string>
<string name="menuReload">Actualiser</string>
<string name="menuClearLog">Effacer le journal maintenant</string>
<string name="logs_cleared">Journal effacé avec succès</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Nije instalirano</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Spremi na SD karticu</string>
<string name="menuSaveLog">"Spremi zapisnik "</string>
<string name="menuReload">Ponovno učitaj</string>
<string name="menuClearLog">Očisti zapisnik sada</string>
<string name="logs_cleared">Zapisnik je uspješno izbrisan</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Non installato</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Salva nella SD</string>
<string name="menuSaveLog">Salva registro</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Pulisci registro eventi</string>
<string name="logs_cleared">Registro eventi creato correttamente</string>

View File

@ -49,7 +49,7 @@
<string name="not_installed">未インストール</string>
<!--Log Fragment-->
<string name="menuSaveToSd">SDカードに保存</string>
<string name="menuSaveLog">ログ保存</string>
<string name="menuReload">リロード</string>
<string name="menuClearLog">ログを消去する</string>
<string name="logs_cleared">ログは正常にクリアされました</string>

View File

@ -49,7 +49,7 @@
<string name="not_installed">설치되지 않음</string>
<!--Log Fragment-->
<string name="menuSaveToSd">SD 카드에 저장</string>
<string name="menuSaveLog">저장 로그</string>
<string name="menuReload">다시 불러오기</string>
<string name="menuClearLog">지금 로그 비우기</string>
<string name="logs_cleared">로그가 성공적으로 비워짐</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Niet geïnstalleerd</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Opslaan op SD-kaart</string>
<string name="menuSaveLog">Opslaan log</string>
<string name="menuReload">Herladen</string>
<string name="menuClearLog">Log nu wissen</string>
<string name="logs_cleared">Log succesvol gewist</string>

View File

@ -59,7 +59,7 @@
<string name="not_installed">Nie zainstalowany</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Zapisz na SD</string>
<string name="menuSaveLog">Zapisz log</string>
<string name="menuReload">Załaduj ponownie</string>
<string name="menuClearLog">Wyczyść Log</string>
<string name="logs_cleared">Log wyczyszczony</string>

View File

@ -59,7 +59,7 @@
<string name="not_installed">Não Instalado</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Salvar no SD</string>
<string name="menuSaveLog">Salvar registro</string>
<string name="menuReload">Recarregar</string>
<string name="menuClearLog">Limpar registro agora</string>
<string name="logs_cleared">Registro limpado com sucesso</string>

View File

@ -55,7 +55,7 @@
<string name="not_installed">Não Instalado</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Gravar no SD</string>
<string name="menuSaveLog">Gravar registo</string>
<string name="menuReload">Recarregar</string>
<string name="menuClearLog">Limpar registo agora</string>
<string name="logs_cleared">Registo limpo com sucesso</string>
@ -91,9 +91,11 @@
<string name="settings_reboot_toast">Reinicie para aplicar definições</string>
<string name="release_notes">Notas da atualização</string>
<string name="repo_cache_cleared">Cache do repositório apagado</string>
<string name="safetyNet_hide_notice">Esta aplicação usa SafetyNet \nJá manipulado pelo MagiskHide por padrão</string>
<string name="safetyNet_hide_notice">Esta aplicação usa SafetyNet
\nJá manipulado pelo MagiskHide por padrão</string>
<string name="process_error">Erro no processo</string>
<string name="internal_storage">O zip foi guardado em: \n[Armazenamento interno]%1$s</string>
<string name="internal_storage">O zip foi guardado em:
\n[Armazenamento interno]%1$s</string>
<string name="zip_download_msg">A transferir ficheiro zip (%1$d%%) …</string>
<string name="zip_process_title">A processar</string>
<string name="zip_process_msg">A processar ficheiro zip …</string>
@ -170,7 +172,8 @@
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Concede acesso total ao seu dispositivo. \nNegue se não tiver certeza!</string>
<string name="su_warning">Concede acesso total ao seu dispositivo.
\nNegue se não tiver certeza!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 minutos</string>

View File

@ -49,7 +49,7 @@
<string name="not_installed">Nu este instalat</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Salvare pe cardul SD</string>
<string name="menuSaveLog">Salvare jurnal</string>
<string name="menuReload">Reîncărcare</string>
<string name="menuClearLog">Șterge jurnal acum</string>
<string name="logs_cleared">Jurnal şters</string>

View File

@ -56,7 +56,7 @@
<string name="not_installed">Не установлен</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Сохранить на карту памяти</string>
<string name="menuSaveLog">"Сохранить историю "</string>
<string name="menuReload">Обновить</string>
<string name="menuClearLog">Очистить историю сейчас</string>
<string name="logs_cleared">История успешно очищена</string>

View File

@ -54,7 +54,7 @@
<string name="not_installed">Inte installerad</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Spara till SD-kort</string>
<string name="menuSaveLog">Spara loggen</string>
<string name="menuReload">Uppdatera</string>
<string name="menuClearLog">Rensa loggen</string>
<string name="logs_cleared">Loggen rensad</string>

View File

@ -54,7 +54,7 @@
<string name="not_installed">Yüklenmemiş</string>
<!--Log Fragment-->
<string name="menuSaveToSd">"SD Kart\'a kaydet"</string>
<string name="menuSaveLog">Günlüğü kaydet</string>
<string name="menuReload">Yenile</string>
<string name="menuClearLog">Günlüğü temizle</string>
<string name="logs_cleared">Günlük başarıyla temizlendi</string>

View File

@ -55,7 +55,7 @@
<string name="not_installed">Не встановлено</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Зберегти на карту пам\'яті</string>
<string name="menuSaveLog">Зберегти логи</string>
<string name="menuReload">Оновити</string>
<string name="menuClearLog">Очистити логи</string>
<string name="logs_cleared">Логи очищено</string>

View File

@ -49,7 +49,7 @@
<string name="not_installed">Chưa được cài đặt</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Lưu vào thẻ nhớ</string>
<string name="menuSaveLog">Lưu nhật ký</string>
<string name="menuReload">Tải lại</string>
<string name="menuClearLog">Xoá nhật ký ngay</string>
<string name="logs_cleared">Đã xoá nhật ký thành công</string>

View File

@ -55,7 +55,7 @@
<string name="not_installed">未安装</string>
<!--Log Fragment-->
<string name="menuSaveToSd">保存到内置存储</string>
<string name="menuSaveLog">保存日志</string>
<string name="menuReload">刷新</string>
<string name="menuClearLog">清除日志</string>
<string name="logs_cleared">日志已成功清除</string>

View File

@ -47,7 +47,7 @@
<string name="not_installed">未安裝</string>
<!--Log Fragment-->
<string name="menuSaveToSd">保存到 SD 卡</string>
<string name="menuSaveLog">保存日誌</string>
<string name="menuReload">重載</string>
<string name="menuClearLog">清除日誌</string>
<string name="logs_cleared">日誌已成功清除</string>

View File

@ -59,7 +59,7 @@
<string name="not_installed">Not Installed</string>
<!--Log Fragment-->
<string name="menuSaveToSd">Save to SD</string>
<string name="menuSaveLog">Save log</string>
<string name="menuReload">Reload</string>
<string name="menuClearLog">Clear log now</string>
<string name="logs_cleared">Log successfully cleared</string>