com.github.chenxiaolong.dualbootpatcher.patcher.PatcherUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.github.chenxiaolong.dualbootpatcher.patcher.PatcherUtils.java

Source

/*
 * Copyright (C) 2014  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.patcher;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.github.chenxiaolong.dualbootpatcher.BuildConfig;
import com.github.chenxiaolong.dualbootpatcher.FileUtils;
import com.github.chenxiaolong.dualbootpatcher.R;
import com.github.chenxiaolong.dualbootpatcher.RomUtils;
import com.github.chenxiaolong.dualbootpatcher.ThreadUtils;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbDevice.Device;
import com.github.chenxiaolong.dualbootpatcher.nativelib.LibMbp.PatcherConfig;
import com.github.chenxiaolong.dualbootpatcher.nativelib.libmiscstuff.LibMiscStuff;

import org.apache.commons.io.Charsets;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

public class PatcherUtils {
    public static final String TAG = PatcherUtils.class.getSimpleName();
    private static final String FILENAME = "data-%s.tar.xz";
    private static final String DIRNAME = "data-%s";

    private static final String PREFIX_DATA_SLOT = "data-slot-";
    private static final String PREFIX_EXTSD_SLOT = "extsd-slot-";

    public static final String PATCHER_ID_MULTIBOOTPATCHER = "MultiBootPatcher";
    public static final String PATCHER_ID_ODINPATCHER = "OdinPatcher";

    private static boolean sInitialized;

    private static Device[] sDevices;
    private static Device sCurrentDevice;

    private static String sTargetFile;
    private static String sTargetDir;

    private static InstallLocation[] sInstallLocations;

    static {
        String version = BuildConfig.VERSION_NAME.split("-")[0];
        sTargetFile = String.format(FILENAME, version);
        sTargetDir = String.format(DIRNAME, version);
    }

    private static File getTargetFile(Context context) {
        return new File(context.getCacheDir() + File.separator + sTargetFile);
    }

    public static File getTargetDirectory(Context context) {
        return new File(context.getFilesDir() + File.separator + sTargetDir);
    }

    public synchronized static void initializePatcher(Context context) {
        if (!sInitialized) {
            extractPatcher(context);
            sInitialized = true;
        }
    }

    public static PatcherConfig newPatcherConfig(Context context) {
        PatcherConfig pc = new PatcherConfig();
        pc.setDataDirectory(getTargetDirectory(context).getAbsolutePath());
        pc.setTempDirectory(context.getCacheDir().getAbsolutePath());
        return pc;
    }

    public synchronized static Device[] getDevices(Context context) {
        ThreadUtils.enforceExecutionOnNonMainThread();
        initializePatcher(context);

        if (sDevices == null) {
            File path = new File(getTargetDirectory(context) + File.separator + "devices.json");
            try {
                String json = org.apache.commons.io.FileUtils.readFileToString(path, Charsets.UTF_8);

                Device[] devices = Device.newListFromJson(json);
                ArrayList<Device> validDevices = new ArrayList<>();

                if (devices != null) {
                    for (Device d : devices) {
                        if (d.validate() == 0) {
                            validDevices.add(d);
                        }
                    }
                }

                if (!validDevices.isEmpty()) {
                    sDevices = validDevices.toArray(new Device[validDevices.size()]);
                }
            } catch (IOException e) {
                Log.w(TAG, "Failed to read " + path, e);
            }
        }

        return sDevices;
    }

    public synchronized static Device getCurrentDevice(Context context) {
        ThreadUtils.enforceExecutionOnNonMainThread();

        if (sCurrentDevice == null) {
            String realCodename = RomUtils.getDeviceCodename(context);
            Device[] devices = getDevices(context);

            if (devices != null) {
                outer: for (Device d : devices) {
                    for (String codename : d.getCodenames()) {
                        if (realCodename.equals(codename)) {
                            sCurrentDevice = d;
                            break outer;
                        }
                    }
                }
            }
        }

        return sCurrentDevice;
    }

    public synchronized static void extractPatcher(Context context) {
        for (File d : context.getCacheDir().listFiles()) {
            if (d.getName().startsWith("DualBootPatcherAndroid") || d.getName().startsWith("tmp")
                    || d.getName().startsWith("data-")) {
                org.apache.commons.io.FileUtils.deleteQuietly(d);
            }
        }
        for (File d : context.getFilesDir().listFiles()) {
            if (d.isDirectory()) {
                for (File t : d.listFiles()) {
                    if (t.getName().contains("tmp")) {
                        org.apache.commons.io.FileUtils.deleteQuietly(t);
                    }
                }
            }
        }

        File targetFile = getTargetFile(context);
        File targetDir = getTargetDirectory(context);

        if (BuildConfig.BUILD_TYPE.equals("debug") || !targetDir.exists()) {
            try {
                FileUtils.extractAsset(context, sTargetFile, targetFile);
            } catch (IOException e) {
                throw new IllegalStateException("Failed to extract data archive from assets", e);
            }

            // Remove all previous files
            for (File d : context.getFilesDir().listFiles()) {
                org.apache.commons.io.FileUtils.deleteQuietly(d);
            }

            try {
                LibMiscStuff.extractArchive(targetFile.getAbsolutePath(), context.getFilesDir().getAbsolutePath());
            } catch (IOException e) {
                throw new IllegalStateException("Failed to extract data archive", e);
            }

            // Delete archive
            targetFile.delete();
        }
    }

    public static class InstallLocation {
        public String id;
        public String name;
        public String description;
    }

    public static InstallLocation[] getInstallLocations(Context context) {
        if (sInstallLocations == null) {
            ArrayList<InstallLocation> locations = new ArrayList<>();

            InstallLocation location = new InstallLocation();
            location.id = "primary";
            location.name = context.getString(R.string.install_location_primary_upgrade);
            location.description = context.getString(R.string.install_location_primary_upgrade_desc);

            locations.add(location);

            location = new InstallLocation();
            location.id = "dual";
            location.name = context.getString(R.string.secondary);
            location.description = String.format(context.getString(R.string.install_location_desc),
                    "/system/multiboot/dual");
            locations.add(location);

            for (int i = 1; i <= 3; i++) {
                location = new InstallLocation();
                location.id = "multi-slot-" + i;
                location.name = String.format(context.getString(R.string.multislot), i);
                location.description = String.format(context.getString(R.string.install_location_desc),
                        "/cache/multiboot/multi-slot-" + i);
                locations.add(location);
            }

            sInstallLocations = locations.toArray(new InstallLocation[locations.size()]);
        }

        return sInstallLocations;
    }

    public static InstallLocation[] getNamedInstallLocations(Context context) {
        ThreadUtils.enforceExecutionOnNonMainThread();

        Log.d(TAG, "Looking for named ROMs");

        File dir = new File(Environment.getExternalStorageDirectory() + File.separator + "MultiBoot");

        ArrayList<InstallLocation> locations = new ArrayList<>();

        File[] files = dir.listFiles();
        if (files != null) {
            for (File f : files) {
                String name = f.getName();

                if (name.startsWith("data-slot-") && !name.equals("data-slot-")) {
                    Log.d(TAG, "- Found data-slot: " + name.substring(10));
                    locations.add(getDataSlotInstallLocation(context, name.substring(10)));
                } else if (name.startsWith("extsd-slot-") && !name.equals("extsd-slot-")) {
                    Log.d(TAG, "- Found extsd-slot: " + name.substring(11));
                    locations.add(getExtsdSlotInstallLocation(context, name.substring(11)));
                }
            }
        } else {
            Log.e(TAG, "Failed to list files in: " + dir);
        }

        return locations.toArray(new InstallLocation[locations.size()]);
    }

    public static InstallLocation getDataSlotInstallLocation(Context context, String dataSlotId) {
        InstallLocation location = new InstallLocation();
        location.id = getDataSlotRomId(dataSlotId);
        location.name = String.format(context.getString(R.string.dataslot), dataSlotId);
        location.description = context.getString(R.string.install_location_desc,
                "/data/multiboot/data-slot-" + dataSlotId);
        return location;
    }

    public static InstallLocation getExtsdSlotInstallLocation(Context context, String extsdSlotId) {
        InstallLocation location = new InstallLocation();
        location.id = getExtsdSlotRomId(extsdSlotId);
        location.name = String.format(context.getString(R.string.extsdslot), extsdSlotId);
        location.description = context.getString(R.string.install_location_desc,
                "[External SD]/multiboot/extsd-slot-" + extsdSlotId);
        return location;
    }

    public static String getDataSlotRomId(String dataSlotId) {
        return PREFIX_DATA_SLOT + dataSlotId;
    }

    public static String getExtsdSlotRomId(String extsdSlotId) {
        return PREFIX_EXTSD_SLOT + extsdSlotId;
    }

    public static boolean isDataSlotRomId(String romId) {
        return romId.startsWith(PREFIX_DATA_SLOT);
    }

    public static boolean isExtsdSlotRomId(String romId) {
        return romId.startsWith(PREFIX_EXTSD_SLOT);
    }

    public static String getDataSlotIdFromRomId(String romId) {
        if (isDataSlotRomId(romId)) {
            return romId.substring(PREFIX_DATA_SLOT.length());
        } else {
            return null;
        }
    }

    public static String getExtsdSlotIdFromRomId(String romId) {
        if (isExtsdSlotRomId(romId)) {
            return romId.substring(PREFIX_EXTSD_SLOT.length());
        } else {
            return null;
        }
    }
}