Java tutorial
/* * Copyright (C) 2015-2016 Andrew Gunnerson <andrewgunnerson@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.github.chenxiaolong.dualbootpatcher.switcher; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.support.annotation.StringRes; import android.support.design.widget.CollapsingToolbarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v4.graphics.ColorUtils; import android.support.v7.app.AppCompatActivity; import android.support.v7.graphics.Palette; import android.support.v7.graphics.Palette.Swatch; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.Toast; import com.github.chenxiaolong.dualbootpatcher.Constants; import com.github.chenxiaolong.dualbootpatcher.FileUtils; import com.github.chenxiaolong.dualbootpatcher.R; import com.github.chenxiaolong.dualbootpatcher.RomUtils; import com.github.chenxiaolong.dualbootpatcher.RomUtils.CacheWallpaperResult; import com.github.chenxiaolong.dualbootpatcher.RomUtils.RomInformation; import com.github.chenxiaolong.dualbootpatcher.SnackbarUtils; import com.github.chenxiaolong.dualbootpatcher.ThreadPoolService.ThreadPoolServiceBinder; import com.github.chenxiaolong.dualbootpatcher.Version; import com.github.chenxiaolong.dualbootpatcher.dialogs.GenericConfirmDialog; import com.github.chenxiaolong.dualbootpatcher.dialogs.GenericProgressDialog; import com.github.chenxiaolong.dualbootpatcher.picasso.PaletteGeneratorCallback; import com.github.chenxiaolong.dualbootpatcher.picasso.PaletteGeneratorTransformation; import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolErrorActivity; import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolUtils; import com.github.chenxiaolong.dualbootpatcher.socket.MbtoolUtils.Feature; import com.github.chenxiaolong.dualbootpatcher.socket.exceptions.MbtoolException.Reason; import com.github.chenxiaolong.dualbootpatcher.socket.interfaces.SetKernelResult; import com.github.chenxiaolong.dualbootpatcher.socket.interfaces.SwitchRomResult; import com.github.chenxiaolong.dualbootpatcher.switcher.AddToHomeScreenOptionsDialog.AddToHomeScreenOptionsDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.BackupNameInputDialog.BackupNameInputDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.BackupRestoreTargetsSelectionDialog.BackupRestoreTargetsSelectionDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.CacheRomThumbnailTask.CacheRomThumbnailTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.ConfirmChecksumIssueDialog.ConfirmChecksumIssueDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.ConfirmMismatchedSetKernelDialog.ConfirmMismatchedSetKernelDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.ActionItem; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.DividerItemDecoration; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.InfoItem; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.Item; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.RomCardItem; import com.github.chenxiaolong.dualbootpatcher.switcher.RomDetailAdapter.RomDetailAdapterListener; import com.github.chenxiaolong.dualbootpatcher.switcher.RomNameInputDialog.RomNameInputDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.SetKernelConfirmDialog.SetKernelConfirmDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.UpdateRamdiskResultDialog.UpdateRamdiskResultDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.WipeTargetsSelectionDialog.WipeTargetsSelectionDialogListener; import com.github.chenxiaolong.dualbootpatcher.switcher.actions.BackupRestoreParams; import com.github.chenxiaolong.dualbootpatcher.switcher.actions.BackupRestoreParams.Action; import com.github.chenxiaolong.dualbootpatcher.switcher.actions.MbtoolAction; import com.github.chenxiaolong.dualbootpatcher.switcher.actions.RomInstallerParams; import com.github.chenxiaolong.dualbootpatcher.switcher.service.CacheWallpaperTask.CacheWallpaperTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.CreateLauncherTask.CreateLauncherTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.GetRomDetailsTask.GetRomDetailsTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.MbtoolTask.MbtoolTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.SetKernelTask.SetKernelTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.SwitchRomTask.SwitchRomTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.CreateRamdiskUpdaterTask.CreateRamdiskUpdaterTaskListener; import com.github.chenxiaolong.dualbootpatcher.switcher.service.WipeRomTask.WipeRomTaskListener; import com.squareup.picasso.Picasso; import com.squareup.picasso.RequestCreator; import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Locale; import mbtool.daemon.v3.MbWipeTarget; public class RomDetailActivity extends AppCompatActivity implements RomNameInputDialogListener, AddToHomeScreenOptionsDialogListener, CacheRomThumbnailTaskListener, RomDetailAdapterListener, ConfirmMismatchedSetKernelDialogListener, SetKernelConfirmDialogListener, UpdateRamdiskResultDialogListener, WipeTargetsSelectionDialogListener, ConfirmChecksumIssueDialogListener, BackupRestoreTargetsSelectionDialogListener, BackupNameInputDialogListener, ServiceConnection { private static final String TAG = RomDetailActivity.class.getSimpleName(); private static final int MENU_EDIT_NAME = Menu.FIRST; private static final int MENU_CHANGE_IMAGE = Menu.FIRST + 1; private static final int MENU_RESET_IMAGE = Menu.FIRST + 2; private static final int INFO_SLOT = 1; private static final int INFO_VERSION = 2; private static final int INFO_BUILD = 3; private static final int INFO_MBTOOL_STATUS = 4; private static final int INFO_APPS_COUNTS = 5; private static final int INFO_SYSTEM_PATH = 6; private static final int INFO_CACHE_PATH = 7; private static final int INFO_DATA_PATH = 8; private static final int INFO_SYSTEM_SIZE = 9; private static final int INFO_CACHE_SIZE = 10; private static final int INFO_DATA_SIZE = 11; private static final int ACTION_UPDATE_RAMDISK = 1; private static final int ACTION_SET_KERNEL = 2; private static final int ACTION_BACKUP = 3; private static final int ACTION_ADD_TO_HOME_SCREEN = 4; private static final int ACTION_WIPE_ROM = 5; private static final String PROGRESS_DIALOG_SWITCH_ROM = RomDetailActivity.class.getCanonicalName() + ".progress.switch_rom"; private static final String PROGRESS_DIALOG_SET_KERNEL = RomDetailActivity.class.getCanonicalName() + ".progress.set_kernel"; private static final String PROGRESS_DIALOG_UPDATE_RAMDISK = RomDetailActivity.class.getCanonicalName() + ".progress.update_ramdisk"; private static final String PROGRESS_DIALOG_WIPE_ROM = RomDetailActivity.class.getCanonicalName() + ".progress.wipe_rom"; private static final String PROGRESS_DIALOG_REBOOT = RomDetailActivity.class.getCanonicalName() + ".progress.reboot"; private static final String CONFIRM_DIALOG_UPDATED_RAMDISK = RomDetailActivity.class.getCanonicalName() + ".confirm.updated_ramdisk"; private static final String CONFIRM_DIALOG_ADD_TO_HOME_SCREEN = RomDetailActivity.class.getCanonicalName() + ".confirm.add_to_home_screen"; private static final String CONFIRM_DIALOG_ROM_NAME = RomDetailActivity.class.getCanonicalName() + ".confirm.rom_name"; private static final String CONFIRM_DIALOG_SET_KERNEL = RomDetailActivity.class.getCanonicalName() + ".confirm.set_kernel"; private static final String CONFIRM_DIALOG_MISMATCHED_KERNEL = RomDetailActivity.class.getCanonicalName() + ".confirm.mismatched_kernel"; private static final String CONFIRM_DIALOG_BACKUP_RESTORE_TARGETS = RomDetailActivity.class.getCanonicalName() + ".confirm.backup_restore_targets"; private static final String CONFIRM_DIALOG_WIPE_TARGETS = RomDetailActivity.class.getCanonicalName() + ".confirm.wipe_targets"; private static final String CONFIRM_DIALOG_CHECKSUM_ISSUE = RomDetailActivity.class.getCanonicalName() + ".confirm.checksum_issue"; private static final String CONFIRM_DIALOG_UNKNOWN_BOOT_PARTITION = RomDetailActivity.class.getCanonicalName() + ".confirm.unknown_boot_partition"; private static final String INPUT_DIALOG_BACKUP_NAME = RomDetailActivity.class.getCanonicalName() + ".input.backup_name"; private static final int REQUEST_IMAGE = 1234; private static final int REQUEST_MBTOOL_ERROR = 2345; // Argument extras public static final String EXTRA_ROM_INFO = "rom_info"; public static final String EXTRA_BOOTED_ROM_INFO = "booted_rom_info"; public static final String EXTRA_ACTIVE_ROM_ID = "active_rom_id"; // Saved state extras private static final String EXTRA_STATE_TASK_ID_CACHE_WALLPAPER = "state.cache_wallpaper"; private static final String EXTRA_STATE_TASK_ID_SWITCH_ROM = "state.switch_rom"; private static final String EXTRA_STATE_TASK_ID_SET_KERNEL = "state.set_kernel"; private static final String EXTRA_STATE_TASK_ID_UPDATE_RAMDISK = "state.update_ramdisk"; private static final String EXTRA_STATE_TASK_ID_WIPE_ROM = "state.wipe_rom"; private static final String EXTRA_STATE_TASK_ID_CREATE_LAUNCHER = "state.create_launcher"; private static final String EXTRA_STATE_TASK_ID_GET_ROM_DETAILS = "state.get_rom_details"; private static final String EXTRA_STATE_TASK_IDS_TO_REMOVE = "state.task_ids_to_reomve"; private static final String EXTRA_STATE_RESULT_INTENT = "state.result_intent"; private static final String EXTRA_STATE_BACKUP_TARGETS = "state.backup_targets"; // Result extras public static final String EXTRA_RESULT_WIPED_ROM = "result.wiped_rom"; private CoordinatorLayout mCoordinator; private CollapsingToolbarLayout mCollapsing; private ImageView mWallpaper; private FloatingActionButton mFab; private RecyclerView mRV; private RomInformation mRomInfo; private RomInformation mBootedRomInfo; private String mActiveRomId; private String[] mBackupTargets; private ArrayList<Item> mItems = new ArrayList<>(); private RomDetailAdapter mAdapter; private static final int FORCE_RAMDISK_UPDATE_TAPS = 7; private int mUpdateRamdiskCountdown; private Toast mUpdateRamdiskToast; private int mUpdateRamdiskResId; private int mTaskIdCacheWallpaper = -1; private int mTaskIdSwitchRom = -1; private int mTaskIdSetKernel = -1; private int mTaskIdUpdateRamdisk = -1; private int mTaskIdWipeRom = -1; private int mTaskIdCreateLauncher = -1; private int mTaskIdGetRomDetails = -1; /** Task IDs to remove */ private ArrayList<Integer> mTaskIdsToRemove = new ArrayList<>(); /** Switcher service */ private SwitcherService mService; /** Callback for events from the service */ private final SwitcherEventCallback mCallback = new SwitcherEventCallback(); /** Handler for processing events from the service on the UI thread */ private final Handler mHandler = new Handler(Looper.getMainLooper()); /** Result intent */ private Intent mResultIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rom_detail); Intent intent = getIntent(); mRomInfo = intent.getParcelableExtra(EXTRA_ROM_INFO); mBootedRomInfo = intent.getParcelableExtra(EXTRA_BOOTED_ROM_INFO); mActiveRomId = intent.getStringExtra(EXTRA_ACTIVE_ROM_ID); if (savedInstanceState != null) { mTaskIdCacheWallpaper = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_CACHE_WALLPAPER); mTaskIdSwitchRom = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_SWITCH_ROM); mTaskIdSetKernel = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_SET_KERNEL); mTaskIdUpdateRamdisk = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_UPDATE_RAMDISK); mTaskIdWipeRom = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_WIPE_ROM); mTaskIdCreateLauncher = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_CREATE_LAUNCHER); mTaskIdGetRomDetails = savedInstanceState.getInt(EXTRA_STATE_TASK_ID_GET_ROM_DETAILS); mTaskIdsToRemove = savedInstanceState.getIntegerArrayList(EXTRA_STATE_TASK_IDS_TO_REMOVE); mResultIntent = savedInstanceState.getParcelable(EXTRA_STATE_RESULT_INTENT); setResult(RESULT_OK, mResultIntent); mBackupTargets = savedInstanceState.getStringArray(EXTRA_STATE_BACKUP_TARGETS); } final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); mCoordinator = (CoordinatorLayout) findViewById(R.id.coordinator); mCollapsing = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); mWallpaper = (ImageView) findViewById(R.id.wallpaper); mFab = (FloatingActionButton) findViewById(R.id.fab); mRV = (RecyclerView) findViewById(R.id.main_rv); mFab.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { switchRom(false); } }); updateTitle(); updateMbtoolStatus(); initializeRecyclerView(); populateRomCardItem(); populateInfoItems(); populateActionItems(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(EXTRA_STATE_TASK_ID_CACHE_WALLPAPER, mTaskIdCacheWallpaper); outState.putInt(EXTRA_STATE_TASK_ID_SWITCH_ROM, mTaskIdSwitchRom); outState.putInt(EXTRA_STATE_TASK_ID_SET_KERNEL, mTaskIdSetKernel); outState.putInt(EXTRA_STATE_TASK_ID_UPDATE_RAMDISK, mTaskIdUpdateRamdisk); outState.putInt(EXTRA_STATE_TASK_ID_WIPE_ROM, mTaskIdWipeRom); outState.putInt(EXTRA_STATE_TASK_ID_CREATE_LAUNCHER, mTaskIdCreateLauncher); outState.putInt(EXTRA_STATE_TASK_ID_GET_ROM_DETAILS, mTaskIdGetRomDetails); outState.putIntegerArrayList(EXTRA_STATE_TASK_IDS_TO_REMOVE, mTaskIdsToRemove); outState.putParcelable(EXTRA_STATE_RESULT_INTENT, mResultIntent); if (mBackupTargets != null) { outState.putStringArray(EXTRA_STATE_BACKUP_TARGETS, mBackupTargets); } } @Override protected void onStart() { super.onStart(); // Start and bind to the service Intent intent = new Intent(this, SwitcherService.class); bindService(intent, this, BIND_AUTO_CREATE); startService(intent); } @Override protected void onStop() { super.onStop(); if (isFinishing()) { if (mTaskIdCacheWallpaper >= 0) { removeCachedTaskId(mTaskIdCacheWallpaper); mTaskIdCacheWallpaper = -1; } if (mTaskIdGetRomDetails >= 0) { removeCachedTaskId(mTaskIdGetRomDetails); mTaskIdGetRomDetails = -1; } } // If we connected to the service and registered the callback, now we unregister it if (mService != null) { if (mTaskIdCacheWallpaper >= 0) { mService.removeCallback(mTaskIdCacheWallpaper, mCallback); } if (mTaskIdSwitchRom >= 0) { mService.removeCallback(mTaskIdSwitchRom, mCallback); } if (mTaskIdSetKernel >= 0) { mService.removeCallback(mTaskIdSetKernel, mCallback); } if (mTaskIdUpdateRamdisk >= 0) { mService.removeCallback(mTaskIdUpdateRamdisk, mCallback); } if (mTaskIdWipeRom >= 0) { mService.removeCallback(mTaskIdWipeRom, mCallback); } if (mTaskIdCreateLauncher >= 0) { mService.removeCallback(mTaskIdCreateLauncher, mCallback); } if (mTaskIdGetRomDetails >= 0) { mService.removeCallback(mTaskIdGetRomDetails, mCallback); } } // Unbind from our service unbindService(this); mService = null; // At this point, the mCallback will not get called anymore by the service. Now we just need // to remove all pending Runnables that were posted to mHandler. mHandler.removeCallbacksAndMessages(null); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // Save a reference to the service so we can interact with it ThreadPoolServiceBinder binder = (ThreadPoolServiceBinder) service; mService = (SwitcherService) binder.getService(); // Remove old task IDs for (int taskId : mTaskIdsToRemove) { mService.removeCachedTask(taskId); } mTaskIdsToRemove.clear(); if (mTaskIdCacheWallpaper < 0) { mTaskIdCacheWallpaper = mService.cacheWallpaper(mRomInfo); mService.addCallback(mTaskIdCacheWallpaper, mCallback); mService.enqueueTaskId(mTaskIdCacheWallpaper); } else { mService.addCallback(mTaskIdCacheWallpaper, mCallback); } if (mTaskIdGetRomDetails < 0) { mTaskIdGetRomDetails = mService.getRomDetails(mRomInfo); mService.addCallback(mTaskIdGetRomDetails, mCallback); mService.enqueueTaskId(mTaskIdGetRomDetails); } else { mService.addCallback(mTaskIdGetRomDetails, mCallback); } if (mTaskIdCreateLauncher >= 0) { mService.addCallback(mTaskIdCreateLauncher, mCallback); } if (mTaskIdSwitchRom >= 0) { mService.addCallback(mTaskIdSwitchRom, mCallback); } if (mTaskIdSetKernel >= 0) { mService.addCallback(mTaskIdSetKernel, mCallback); } if (mTaskIdUpdateRamdisk >= 0) { mService.addCallback(mTaskIdUpdateRamdisk, mCallback); } if (mTaskIdWipeRom >= 0) { mService.addCallback(mTaskIdWipeRom, mCallback); } } @Override public void onServiceDisconnected(ComponentName name) { mService = null; } private void removeCachedTaskId(int taskId) { if (mService != null) { mService.removeCachedTask(taskId); } else { mTaskIdsToRemove.add(taskId); } } private void updateTitle() { mCollapsing.setTitle(mRomInfo.getId()); } private void updateMbtoolStatus() { // There is currently no way to determine the mbtool version of other ROMs if (mBootedRomInfo != null && mBootedRomInfo.getId().equals(mRomInfo.getId())) { Version minAppSharing = MbtoolUtils.getMinimumRequiredVersion(Feature.APP_SHARING); Version minDaemon = MbtoolUtils.getMinimumRequiredVersion(Feature.DAEMON); Version version = MbtoolUtils.getSystemMbtoolVersion(this); if (version.compareTo(minAppSharing) >= 0 && version.compareTo(minDaemon) >= 0) { mUpdateRamdiskCountdown = FORCE_RAMDISK_UPDATE_TAPS; mUpdateRamdiskResId = R.string.update_ramdisk_up_to_date_desc; } else { mUpdateRamdiskCountdown = -1; if (version.equals(Version.from("0.0.0"))) { mUpdateRamdiskResId = R.string.update_ramdisk_missing_desc; } else { mUpdateRamdiskResId = R.string.update_ramdisk_outdated_desc; } } } else { mUpdateRamdiskCountdown = -1; mUpdateRamdiskResId = R.string.unknown; } } private void initializeRecyclerView() { mAdapter = new RomDetailAdapter(mItems, this); mRV.setHasFixedSize(true); mRV.setAdapter(mAdapter); mRV.setLayoutManager(new LinearLayoutManager(this)); mRV.addItemDecoration(new DividerItemDecoration(this)); } private void populateRomCardItem() { RomCardItem item = new RomCardItem(mRomInfo); mItems.add(item); } private void populateInfoItems() { mItems.add(new InfoItem(INFO_SLOT, getString(R.string.rom_details_info_slot), mRomInfo.getId())); mItems.add(new InfoItem(INFO_VERSION, getString(R.string.rom_details_info_version), mRomInfo.getVersion())); mItems.add(new InfoItem(INFO_BUILD, getString(R.string.rom_details_info_build), mRomInfo.getBuild())); mItems.add(new InfoItem(INFO_MBTOOL_STATUS, getString(R.string.rom_details_info_mbtool_status), getString(mUpdateRamdiskResId))); mItems.add(new InfoItem(INFO_APPS_COUNTS, getString(R.string.rom_details_info_apps_counts), getString(R.string.rom_details_info_calculating))); mItems.add(new InfoItem(INFO_SYSTEM_PATH, getString(R.string.rom_details_info_system_path), mRomInfo.getSystemPath())); mItems.add(new InfoItem(INFO_CACHE_PATH, getString(R.string.rom_details_info_cache_path), mRomInfo.getCachePath())); mItems.add(new InfoItem(INFO_DATA_PATH, getString(R.string.rom_details_info_data_path), mRomInfo.getDataPath())); mItems.add(new InfoItem(INFO_SYSTEM_SIZE, getString(R.string.rom_details_info_system_size), getString(R.string.rom_details_info_calculating))); mItems.add(new InfoItem(INFO_CACHE_SIZE, getString(R.string.rom_details_info_cache_size), getString(R.string.rom_details_info_calculating))); mItems.add(new InfoItem(INFO_DATA_SIZE, getString(R.string.rom_details_info_data_size), getString(R.string.rom_details_info_calculating))); } private void populateActionItems() { mItems.add(new ActionItem(ACTION_UPDATE_RAMDISK, R.drawable.rom_details_action_update_ramdisk, getString(R.string.rom_menu_update_ramdisk))); mItems.add(new ActionItem(ACTION_SET_KERNEL, R.drawable.rom_details_action_set_kernel, getString(R.string.rom_menu_set_kernel))); mItems.add(new ActionItem(ACTION_BACKUP, R.drawable.rom_details_action_backup, getString(R.string.rom_menu_backup_rom))); mItems.add(new ActionItem(ACTION_ADD_TO_HOME_SCREEN, R.drawable.rom_details_action_home, getString(R.string.rom_menu_add_to_home_screen))); mItems.add(new ActionItem(ACTION_WIPE_ROM, R.drawable.rom_details_action_wipe, getString(R.string.rom_menu_wipe_rom))); } private void setInfoItem(int id, String newValue) { for (int i = 0; i < mItems.size(); i++) { Item item = mItems.get(i); if (item instanceof InfoItem) { InfoItem infoItem = (InfoItem) item; if (infoItem.id == id) { infoItem.value = newValue; } mAdapter.notifyItemChanged(i); } } } private void reloadThumbnail() { for (int i = 0; i < mItems.size(); i++) { Item item = mItems.get(i); if (item instanceof RomCardItem) { mAdapter.notifyItemChanged(i); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_EDIT_NAME, Menu.NONE, R.string.rom_menu_edit_name); menu.add(0, MENU_CHANGE_IMAGE, Menu.NONE, R.string.rom_menu_change_image); menu.add(0, MENU_RESET_IMAGE, Menu.NONE, R.string.rom_menu_reset_image); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; case MENU_EDIT_NAME: onSelectedEditName(); return true; case MENU_CHANGE_IMAGE: onSelectedChangeImage(); return true; case MENU_RESET_IMAGE: onSelectedResetImage(); return true; } return super.onOptionsItemSelected(item); } @Override public void onActivityResult(int request, int result, Intent data) { switch (request) { case REQUEST_IMAGE: if (data != null && result == RESULT_OK) { new CacheRomThumbnailTask(getApplicationContext(), mRomInfo, data.getData(), this).execute(); } break; case REQUEST_MBTOOL_ERROR: if (data != null && result == RESULT_OK) { finish(); } break; default: super.onActivityResult(request, result, data); break; } } private void onSelectedEditName() { RomNameInputDialog d = RomNameInputDialog.newInstanceFromActivity(mRomInfo); d.show(getFragmentManager(), CONFIRM_DIALOG_ROM_NAME); } private void onSelectedChangeImage() { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); intent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(intent, REQUEST_IMAGE); } private void onSelectedResetImage() { File f = new File(mRomInfo.getThumbnailPath()); if (f.isFile()) { f.delete(); } reloadThumbnail(); } public void onSelectedAddToHomeScreen() { AddToHomeScreenOptionsDialog d = AddToHomeScreenOptionsDialog.newInstanceFromActivity(mRomInfo); d.show(getFragmentManager(), CONFIRM_DIALOG_ADD_TO_HOME_SCREEN); } public void onSelectedUpdateRamdisk() { // Act like the Android settings app :) if (mUpdateRamdiskCountdown > 0) { if (mUpdateRamdiskCountdown == FORCE_RAMDISK_UPDATE_TAPS) { createSnackbar(mUpdateRamdiskResId, Snackbar.LENGTH_LONG).show(); } mUpdateRamdiskCountdown--; if (mUpdateRamdiskCountdown == 0) { if (mUpdateRamdiskToast != null) { mUpdateRamdiskToast.cancel(); } mUpdateRamdiskToast = Toast.makeText(this, R.string.force_updating_ramdisk, Toast.LENGTH_LONG); mUpdateRamdiskToast.show(); createRamdiskUpdater(); mUpdateRamdiskCountdown = FORCE_RAMDISK_UPDATE_TAPS; } else if (mUpdateRamdiskCountdown > 0 && mUpdateRamdiskCountdown < (FORCE_RAMDISK_UPDATE_TAPS - 2)) { if (mUpdateRamdiskToast != null) { mUpdateRamdiskToast.cancel(); } mUpdateRamdiskToast = Toast.makeText(this, getResources().getQuantityString(R.plurals.force_update_ramdisk_countdown, mUpdateRamdiskCountdown, mUpdateRamdiskCountdown), Toast.LENGTH_SHORT); mUpdateRamdiskToast.show(); } } else if (mUpdateRamdiskCountdown < 0) { // Already enabled if (mUpdateRamdiskToast != null) { mUpdateRamdiskToast.cancel(); } createRamdiskUpdater(); } } public void onSelectedSetKernel() { // Ask for confirmation if (mActiveRomId != null && !mActiveRomId.equals(mRomInfo.getId())) { ConfirmMismatchedSetKernelDialog d = ConfirmMismatchedSetKernelDialog .newInstanceFromActivity(mActiveRomId, mRomInfo.getId()); d.show(getFragmentManager(), CONFIRM_DIALOG_MISMATCHED_KERNEL); } else { SetKernelConfirmDialog d = SetKernelConfirmDialog.newInstanceFromActivity(mRomInfo); d.show(getFragmentManager(), CONFIRM_DIALOG_SET_KERNEL); } } public void onSelectedBackupRom() { BackupRestoreTargetsSelectionDialog d = BackupRestoreTargetsSelectionDialog .newInstanceFromActivity(Action.BACKUP); d.show(getFragmentManager(), CONFIRM_DIALOG_BACKUP_RESTORE_TARGETS); } public void onSelectedWipeRom() { if (mBootedRomInfo != null && mBootedRomInfo.getId().equals(mRomInfo.getId())) { createSnackbar(R.string.wipe_rom_no_wipe_current_rom, Snackbar.LENGTH_LONG).show(); } else { WipeTargetsSelectionDialog d = WipeTargetsSelectionDialog.newInstanceFromActivity(); d.show(getFragmentManager(), CONFIRM_DIALOG_WIPE_TARGETS); } } @Override public void onRomNameChanged(String newName) { mRomInfo.setName(newName); new Thread() { @Override public void run() { RomUtils.saveConfig(mRomInfo); } }.start(); updateTitle(); } @Override public void onConfirmAddToHomeScreenOptions(RomInformation info, boolean reboot) { mTaskIdCreateLauncher = mService.createLauncher(info, reboot); mService.addCallback(mTaskIdCreateLauncher, mCallback); mService.enqueueTaskId(mTaskIdCreateLauncher); } @Override public void onConfirmMismatchedSetKernel() { setKernel(); } @Override public void onConfirmChecksumIssue(String romId) { switchRom(true); } @Override public void onConfirmSetKernel() { setKernel(); } @Override public void onConfirmUpdatedRamdisk(boolean reboot) { if (reboot) { GenericProgressDialog.Builder builder = new GenericProgressDialog.Builder(); builder.message(R.string.please_wait); builder.build().show(getFragmentManager(), PROGRESS_DIALOG_REBOOT); new Thread() { @Override public void run() { SwitcherUtils.reboot(getApplicationContext()); } }.start(); } } @Override public void onSelectedBackupRestoreTargets(String[] targets) { if (targets.length == 0) { createSnackbar(R.string.br_no_target_selected, Snackbar.LENGTH_LONG).show(); return; } mBackupTargets = targets; DateFormat df = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss", Locale.US); String suggestedName = df.format(new Date()) + '_' + mRomInfo.getId(); // Prompt for back up name BackupNameInputDialog d = BackupNameInputDialog.newInstanceFromActivity(suggestedName); d.show(getFragmentManager(), INPUT_DIALOG_BACKUP_NAME); } @Override public void onSelectedBackupName(String name) { SharedPreferences prefs = getSharedPreferences("settings", 0); Uri backupDirUri = Uri.parse(prefs.getString(Constants.Preferences.BACKUP_DIRECTORY_URI, Constants.Defaults.BACKUP_DIRECTORY_URI)); BackupRestoreParams params = new BackupRestoreParams(Action.BACKUP, mRomInfo.getId(), mBackupTargets, name, backupDirUri, false); MbtoolAction action = new MbtoolAction(params); // Start backup Intent intent = new Intent(this, MbtoolTaskOutputActivity.class); intent.putExtra(MbtoolTaskOutputFragment.PARAM_ACTIONS, new MbtoolAction[] { action }); startActivity(intent); } @Override public void onSelectedWipeTargets(short[] targets) { if (targets.length == 0) { createSnackbar(R.string.wipe_rom_none_selected, Snackbar.LENGTH_LONG).show(); return; } wipeRom(targets); } @Override public void onRomThumbnailCached(RomInformation info) { reloadThumbnail(); } @Override public void onActionItemSelected(ActionItem item) { switch (item.id) { case ACTION_UPDATE_RAMDISK: onSelectedUpdateRamdisk(); break; case ACTION_SET_KERNEL: onSelectedSetKernel(); break; case ACTION_BACKUP: onSelectedBackupRom(); break; case ACTION_ADD_TO_HOME_SCREEN: onSelectedAddToHomeScreen(); break; case ACTION_WIPE_ROM: onSelectedWipeRom(); break; default: throw new IllegalStateException("Invalid action ID: " + item.id); } } private void onCachedWallpaper(CacheWallpaperResult result) { File wallpaperFile = new File(mRomInfo.getWallpaperPath()); RequestCreator creator; if (result == CacheWallpaperResult.USES_LIVE_WALLPAPER) { Toast.makeText(this, "Cannot preview live wallpaper", Toast.LENGTH_SHORT).show(); } if (result == CacheWallpaperResult.UP_TO_DATE || result == CacheWallpaperResult.UPDATED) { creator = Picasso.with(this).load(wallpaperFile).error(R.drawable.material); } else { creator = Picasso.with(this).load(R.drawable.material); } creator.transform(PaletteGeneratorTransformation.getInstance()).into(mWallpaper, new PaletteGeneratorCallback(mWallpaper) { @Override public void onObtainedPalette(Palette palette) { if (palette == null) { return; } Swatch swatch = palette.getMutedSwatch(); if (swatch == null) { swatch = palette.getDarkVibrantSwatch(); } if (swatch != null) { // Status bar should be slightly darker float[] hsl = swatch.getHsl(); hsl[2] -= 0.05; if (hsl[2] < 0) { hsl[2] = 0; } mCollapsing.setContentScrimColor(swatch.getRgb()); mCollapsing.setStatusBarScrimColor(ColorUtils.HSLToColor(hsl)); mFab.setBackgroundTintList(ColorStateList.valueOf(swatch.getRgb())); } //Swatch lightVibrant = palette.getLightVibrantSwatch(); //if (lightVibrant != null) { // collapsingToolbar.setCollapsedTitleTextColor(lightVibrant.getRgb()); // collapsingToolbar.setExpandedTitleColor(lightVibrant.getRgb()); //} } }); } private void onSwitchedRom(SwitchRomResult result) { // Remove cached task from service removeCachedTaskId(mTaskIdSwitchRom); mTaskIdSwitchRom = -1; GenericProgressDialog d = (GenericProgressDialog) getFragmentManager() .findFragmentByTag(PROGRESS_DIALOG_SWITCH_ROM); if (d != null) { d.dismiss(); } switch (result) { case SUCCEEDED: createSnackbar(R.string.choose_rom_success, Snackbar.LENGTH_LONG).show(); Log.d(TAG, "Prior cached boot partition ROM ID was: " + mActiveRomId); mActiveRomId = mRomInfo.getId(); Log.d(TAG, "Changing cached boot partition ROM ID to: " + mActiveRomId); break; case FAILED: createSnackbar(R.string.choose_rom_failure, Snackbar.LENGTH_LONG).show(); break; case CHECKSUM_INVALID: createSnackbar(R.string.choose_rom_checksums_invalid, Snackbar.LENGTH_LONG).show(); showChecksumIssueDialog(ConfirmChecksumIssueDialog.CHECKSUM_INVALID, mRomInfo.getId()); break; case CHECKSUM_NOT_FOUND: createSnackbar(R.string.choose_rom_checksums_missing, Snackbar.LENGTH_LONG).show(); showChecksumIssueDialog(ConfirmChecksumIssueDialog.CHECKSUM_MISSING, mRomInfo.getId()); break; case UNKNOWN_BOOT_PARTITION: showUnknownBootPartitionDialog(); break; } } private void onSetKernel(SetKernelResult result) { // Remove cached task from service removeCachedTaskId(mTaskIdSetKernel); mTaskIdSetKernel = -1; GenericProgressDialog d = (GenericProgressDialog) getFragmentManager() .findFragmentByTag(PROGRESS_DIALOG_SET_KERNEL); if (d != null) { d.dismiss(); } switch (result) { case SUCCEEDED: createSnackbar(R.string.set_kernel_success, Snackbar.LENGTH_LONG).show(); break; case FAILED: createSnackbar(R.string.set_kernel_failure, Snackbar.LENGTH_LONG).show(); break; case UNKNOWN_BOOT_PARTITION: showUnknownBootPartitionDialog(); break; } } private void onCreatedRamdiskUpdater(String path) { // Remove cached task from service removeCachedTaskId(mTaskIdUpdateRamdisk); mTaskIdUpdateRamdisk = -1; if (path == null) { hideRamdiskUpdateProgressDialog(); showRamdiskUpdateCompletionDialog(false); } else { flashRamdiskUpdater(path); } } private void onFlashedRamdiskUpdater(boolean success) { // Remove cached task from service removeCachedTaskId(mTaskIdUpdateRamdisk); mTaskIdUpdateRamdisk = -1; hideRamdiskUpdateProgressDialog(); showRamdiskUpdateCompletionDialog(success); } private void onWipedRom(short[] succeeded, short[] failed) { // Remove cached task from service removeCachedTaskId(mTaskIdWipeRom); mTaskIdWipeRom = -1; GenericProgressDialog d = (GenericProgressDialog) getFragmentManager() .findFragmentByTag(PROGRESS_DIALOG_WIPE_ROM); if (d != null) { d.dismiss(); } if (succeeded == null || failed == null) { createSnackbar(R.string.wipe_rom_initiate_fail, Snackbar.LENGTH_LONG).show(); } else { StringBuilder sb = new StringBuilder(); if (succeeded.length > 0) { sb.append( String.format(getString(R.string.wipe_rom_successfully_wiped), targetsToString(succeeded))); if (failed.length > 0) { sb.append("\n"); } } if (failed.length > 0) { sb.append(String.format(getString(R.string.wipe_rom_failed_to_wipe), targetsToString(failed))); } createSnackbar(sb.toString(), Snackbar.LENGTH_LONG).show(); } // Alert parent activity if (mResultIntent == null) { mResultIntent = new Intent(); } mResultIntent.putExtra(EXTRA_RESULT_WIPED_ROM, true); setResult(RESULT_OK, mResultIntent); } private void onCreatedLauncher() { // Remove cached task from service removeCachedTaskId(mTaskIdCreateLauncher); mTaskIdCreateLauncher = -1; createSnackbar(String.format(getString(R.string.successfully_created_launcher), mRomInfo.getName()), Snackbar.LENGTH_LONG).show(); } private void onHaveSystemSize(boolean success, long size) { if (success) { setInfoItem(INFO_SYSTEM_SIZE, FileUtils.toHumanReadableSize(this, size, 2)); } else { setInfoItem(INFO_SYSTEM_SIZE, getString(R.string.unknown)); } } private void onHaveCacheSize(boolean success, long size) { if (success) { setInfoItem(INFO_CACHE_SIZE, FileUtils.toHumanReadableSize(this, size, 2)); } else { setInfoItem(INFO_CACHE_SIZE, getString(R.string.unknown)); } } private void onHaveDataSize(boolean success, long size) { if (success) { setInfoItem(INFO_DATA_SIZE, FileUtils.toHumanReadableSize(this, size, 2)); } else { setInfoItem(INFO_DATA_SIZE, getString(R.string.unknown)); } } private void onHavePackagesCounts(boolean success, int systemPackages, int updatedPackages, int userPackages) { if (success) { setInfoItem(INFO_APPS_COUNTS, getString(R.string.rom_details_info_apps_counts_value, systemPackages, updatedPackages, userPackages)); } else { setInfoItem(INFO_APPS_COUNTS, getString(R.string.unknown)); } } private void switchRom(boolean forceChecksumsUpdate) { GenericProgressDialog.Builder builder = new GenericProgressDialog.Builder(); builder.title(R.string.switching_rom); builder.message(R.string.please_wait); builder.build().show(getFragmentManager(), PROGRESS_DIALOG_SWITCH_ROM); mTaskIdSwitchRom = mService.switchRom(mRomInfo.getId(), forceChecksumsUpdate); mService.addCallback(mTaskIdSwitchRom, mCallback); mService.enqueueTaskId(mTaskIdSwitchRom); } private void setKernel() { GenericProgressDialog.Builder builder = new GenericProgressDialog.Builder(); builder.title(R.string.setting_kernel); builder.message(R.string.please_wait); builder.build().show(getFragmentManager(), PROGRESS_DIALOG_SET_KERNEL); mTaskIdSetKernel = mService.setKernel(mRomInfo.getId()); mService.addCallback(mTaskIdSetKernel, mCallback); mService.enqueueTaskId(mTaskIdSetKernel); } private void createRamdiskUpdater() { showRamdiskUpdateProgressDialog(); mTaskIdUpdateRamdisk = mService.createRamdiskUpdater(mRomInfo); mService.addCallback(mTaskIdUpdateRamdisk, mCallback); mService.enqueueTaskId(mTaskIdUpdateRamdisk); } private void flashRamdiskUpdater(String path) { File file = new File(path); RomInstallerParams params = new RomInstallerParams(Uri.fromFile(file), file.getName(), mRomInfo.getId()); params.setSkipMounts(true); params.setAllowOverwrite(true); mTaskIdUpdateRamdisk = mService.mbtoolActions(new MbtoolAction[] { new MbtoolAction(params) }); mService.addCallback(mTaskIdUpdateRamdisk, mCallback); mService.enqueueTaskId(mTaskIdUpdateRamdisk); } private void wipeRom(short[] targets) { GenericProgressDialog.Builder builder = new GenericProgressDialog.Builder(); builder.title(R.string.wiping_targets); builder.message(R.string.please_wait); builder.build().show(getFragmentManager(), PROGRESS_DIALOG_WIPE_ROM); mTaskIdWipeRom = mService.wipeRom(mRomInfo.getId(), targets); mService.addCallback(mTaskIdWipeRom, mCallback); mService.enqueueTaskId(mTaskIdWipeRom); } private void showChecksumIssueDialog(int issue, String romId) { ConfirmChecksumIssueDialog d = ConfirmChecksumIssueDialog.newInstanceFromActivity(issue, romId); d.show(getFragmentManager(), CONFIRM_DIALOG_CHECKSUM_ISSUE); } private void showUnknownBootPartitionDialog() { String codename = RomUtils.getDeviceCodename(this); String message = String.format(getString(R.string.unknown_boot_partition), codename); GenericConfirmDialog.Builder builder = new GenericConfirmDialog.Builder(); builder.message(message); builder.buttonText(R.string.ok); builder.build().show(getFragmentManager(), CONFIRM_DIALOG_UNKNOWN_BOOT_PARTITION); } private void showRamdiskUpdateProgressDialog() { GenericProgressDialog.Builder builder = new GenericProgressDialog.Builder(); builder.message(R.string.please_wait); builder.build().show(getFragmentManager(), PROGRESS_DIALOG_UPDATE_RAMDISK); } private void hideRamdiskUpdateProgressDialog() { GenericProgressDialog d = (GenericProgressDialog) getFragmentManager() .findFragmentByTag(PROGRESS_DIALOG_UPDATE_RAMDISK); if (d != null) { d.dismiss(); } } private void showRamdiskUpdateCompletionDialog(boolean success) { boolean isCurrentRom = mBootedRomInfo != null && mBootedRomInfo.getId().equals(mRomInfo.getId()); UpdateRamdiskResultDialog dialog = UpdateRamdiskResultDialog.newInstanceFromActivity(success, isCurrentRom); dialog.show(getFragmentManager(), CONFIRM_DIALOG_UPDATED_RAMDISK); } private Snackbar createSnackbar(String text, int duration) { return SnackbarUtils.createSnackbar(this, mCoordinator, text, duration); } private Snackbar createSnackbar(@StringRes int resId, int duration) { return SnackbarUtils.createSnackbar(this, mCoordinator, resId, duration); } private String targetsToString(short[] targets) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < targets.length; i++) { if (i != 0) { sb.append(", "); } if (targets[i] == MbWipeTarget.SYSTEM) { sb.append(getString(R.string.wipe_target_system)); } else if (targets[i] == MbWipeTarget.CACHE) { sb.append(getString(R.string.wipe_target_cache)); } else if (targets[i] == MbWipeTarget.DATA) { sb.append(getString(R.string.wipe_target_data)); } else if (targets[i] == MbWipeTarget.DALVIK_CACHE) { sb.append(getString(R.string.wipe_target_dalvik_cache)); } else if (targets[i] == MbWipeTarget.MULTIBOOT) { sb.append(getString(R.string.wipe_target_multiboot_files)); } } return sb.toString(); } private class SwitcherEventCallback implements CacheWallpaperTaskListener, SwitchRomTaskListener, SetKernelTaskListener, CreateRamdiskUpdaterTaskListener, WipeRomTaskListener, CreateLauncherTaskListener, GetRomDetailsTaskListener, MbtoolTaskListener { @Override public void onCachedWallpaper(int taskId, RomInformation romInfo, final CacheWallpaperResult result) { if (taskId == mTaskIdCacheWallpaper) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onCachedWallpaper(result); } }); } } @Override public void onSwitchedRom(int taskId, String romId, final SwitchRomResult result) { if (taskId == mTaskIdSwitchRom) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onSwitchedRom(result); } }); } } @Override public void onSetKernel(int taskId, String romId, final SetKernelResult result) { if (taskId == mTaskIdSetKernel) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onSetKernel(result); } }); } } @Override public void onCreatedRamdiskUpdater(int taskId, RomInformation romInfo, final String path) { if (taskId == mTaskIdUpdateRamdisk) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onCreatedRamdiskUpdater(path); } }); } } @Override public void onWipedRom(int taskId, String romId, final short[] succeeded, final short[] failed) { if (taskId == mTaskIdWipeRom) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onWipedRom(succeeded, failed); } }); } } @Override public void onCreatedLauncher(int taskId, RomInformation romInfo) { if (taskId == mTaskIdCreateLauncher) { mHandler.post(new Runnable() { @Override public void run() { RomDetailActivity.this.onCreatedLauncher(); } }); } } @Override public void onRomDetailsGotSystemSize(int taskId, RomInformation romInfo, final boolean success, final long size) { if (taskId == mTaskIdGetRomDetails) { mHandler.post(new Runnable() { @Override public void run() { onHaveSystemSize(success, size); } }); } } @Override public void onRomDetailsGotCacheSize(int taskId, RomInformation romInfo, final boolean success, final long size) { if (taskId == mTaskIdGetRomDetails) { mHandler.post(new Runnable() { @Override public void run() { onHaveCacheSize(success, size); } }); } } @Override public void onRomDetailsGotDataSize(int taskId, RomInformation romInfo, final boolean success, final long size) { if (taskId == mTaskIdGetRomDetails) { mHandler.post(new Runnable() { @Override public void run() { onHaveDataSize(success, size); } }); } } @Override public void onRomDetailsGotPackagesCounts(int taskId, RomInformation romInfo, final boolean success, final int systemPackages, final int updatedPackages, final int userPackages) { if (taskId == mTaskIdGetRomDetails) { mHandler.post(new Runnable() { @Override public void run() { onHavePackagesCounts(success, systemPackages, updatedPackages, userPackages); } }); } } @Override public void onRomDetailsFinished(int taskId, RomInformation romInfo) { // Ignore } @Override public void onMbtoolConnectionFailed(int taskId, final Reason reason) { mHandler.post(new Runnable() { @Override public void run() { Intent intent = new Intent(RomDetailActivity.this, MbtoolErrorActivity.class); intent.putExtra(MbtoolErrorActivity.EXTRA_REASON, reason); startActivityForResult(intent, REQUEST_MBTOOL_ERROR); } }); } @Override public void onMbtoolTasksCompleted(int taskId, MbtoolAction[] actions, final int attempted, final int succeeded) { if (taskId == mTaskIdUpdateRamdisk) { mHandler.post(new Runnable() { @Override public void run() { onFlashedRamdiskUpdater(attempted == succeeded); } }); } } @Override public void onCommandOutput(int taskId, String line) { Log.d(TAG, "[Ramdisk update flasher] " + line); } } }