Java tutorial
/* * Copyright (C) 2015 Joker * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.kiva.ohmylinux; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.AppCompatCheckBox; import android.support.v7.widget.AppCompatEditText; import android.support.v7.widget.AppCompatSpinner; import android.support.v7.widget.AppCompatTextView; import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ScrollView; import com.kiva.ohmylinux.adapter.ProfileAdapter; import com.kiva.ohmylinux.profile.LinuxProfile; import com.kiva.ohmylinux.profile.ProfileManager; import com.kiva.ohmylinux.utils.AppUtils; import com.kiva.ohmylinux.utils.FileUtils; import com.kiva.ohmylinux.utils.L; import com.kiva.ohmylinux.utils.LaunchUtils; import com.kiva.ohmylinux.utils.ResourceUtils; import com.kiva.ohmylinux.view.FileSystemTypeSpinner; import java.io.File; import java.util.List; import java.util.UUID; /** * @author Kiva * @date 2015/12/8 */ public class MainActivity extends AppCompatActivity implements L.LogCallback { private static final int REQ_FIND_DEVICE_PATH = 0; private static final int REQ_FIND_DISK_TABLE = 1; private static final int STATUS_EDITING = 0; private static final int STATUS_NORMAL = 1; private DrawerLayout drawer; private ActionBarDrawerToggle drawerToggle; private FloatingActionButton floatingButton; private ListView profileListView; private ProfileAdapter profileListAdapter; private ScrollView logScrollView; private AppCompatTextView logTextView; private AppCompatEditText editNickName, editDevicePath, editMountPoint, editDiskTableFile, editInitProgram, editInitProgramArgs; private FileSystemTypeSpinner editFsType; private AppCompatCheckBox editMountSd0, editMountSd1; private AppCompatButton editFindDevicePath, editFindDiskTableFile; private LinearLayout editLayout, defaultLayout; private LinuxProfile currentProfile; private int status = STATUS_NORMAL; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); loadProfile(); ResourceUtils.initResources(this); } /** * ? */ private void loadProfile() { List<LinuxProfile> list = ProfileManager.getInstance().scanProfile(); L.d("found " + list.size() + " profile(s)"); profileListAdapter = new ProfileAdapter(this, list); profileListView.setAdapter(profileListAdapter); } private void initView() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); logScrollView = (ScrollView) findViewById(R.id.mainLogScrollView); logTextView = (AppCompatTextView) findViewById(R.id.mainLogText); L.setLogCallback(this); floatingButton = (FloatingActionButton) findViewById(R.id.fab); floatingButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (status == STATUS_NORMAL) { final String[] items = getResources().getStringArray(R.array.fab_actions); new AlertDialog.Builder(MainActivity.this).setTitle(R.string.action_new) .setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: // new iamge doCreateNewImage(); break; case 1: // new profile doCreateNewProfile(); break; } } }).setPositiveButton(android.R.string.no, null).show(); } else if (status == STATUS_EDITING) { doClose(); } } }); drawer = (DrawerLayout) findViewById(R.id.mainDrawerLayout); drawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close); drawerToggle.setDrawerIndicatorEnabled(true); drawer.setDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerSlide(View drawerView, float slideOffset) { drawerToggle.onDrawerSlide(drawerView, slideOffset); } @Override public void onDrawerOpened(View drawerView) { drawerToggle.onDrawerOpened(drawerView); floatingButton.hide(); if (drawer.isDrawerOpen(GravityCompat.START)) { if (profileListAdapter.getCount() == 0) { setTitle(R.string.no_profile); } else { setTitle(R.string.profiles); } } else if (drawer.isDrawerOpen(GravityCompat.END)) { setTitle(R.string.log_console); } } @Override public void onDrawerClosed(View drawerView) { drawerToggle.onDrawerClosed(drawerView); floatingButton.show(); if (!drawer.isDrawerOpen(GravityCompat.START) && !drawer.isDrawerOpen(GravityCompat.END)) { setTitle(R.string.app_name); } } @Override public void onDrawerStateChanged(int newState) { drawerToggle.onDrawerStateChanged(newState); } }); drawerToggle.syncState(); profileListView = (ListView) findViewById(R.id.mainProfileListView); profileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { drawer.closeDrawer(GravityCompat.START); LinuxProfile profile = (LinuxProfile) profileListAdapter.getItem(position); doSelectProfile(profile); } }); profileListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { LinuxProfile profile = (LinuxProfile) profileListAdapter.getItem(position); doShowOptions(profile); return true; } }); editLayout = (LinearLayout) findViewById(R.id.mainEditLayout); defaultLayout = (LinearLayout) findViewById(R.id.mainDefaultLayout); editNickName = (AppCompatEditText) findViewById(R.id.mainEditNickName); editDevicePath = (AppCompatEditText) findViewById(R.id.mainEditDevicePath); editMountPoint = (AppCompatEditText) findViewById(R.id.mainEditMountPoint); editDiskTableFile = (AppCompatEditText) findViewById(R.id.mainEditDiskTableFile); editInitProgram = (AppCompatEditText) findViewById(R.id.mainEditInitProgram); editInitProgramArgs = (AppCompatEditText) findViewById(R.id.mainEditInitProgramArgs); editFindDevicePath = (AppCompatButton) findViewById(R.id.mainEditFindDevicePath); editFindDiskTableFile = (AppCompatButton) findViewById(R.id.mainEditFindDiskTableFile); editMountSd0 = (AppCompatCheckBox) findViewById(R.id.mainEditMountSd0); editMountSd1 = (AppCompatCheckBox) findViewById(R.id.mainEditMountSd1); editFsType = (FileSystemTypeSpinner) findViewById(R.id.mainEditFsType); editNickName.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { if (currentProfile == null) { return; } String newName = editNickName.getText().toString(); if (newName.isEmpty()) { return; } currentProfile.setNickName(newName); editMountPoint.setText(currentProfile.getMountPoint()); } }); editFindDevicePath.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AppUtils.openFileBrowser(MainActivity.this, REQ_FIND_DEVICE_PATH); } }); editFindDiskTableFile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AppUtils.openFileBrowser(MainActivity.this, REQ_FIND_DISK_TABLE); } }); } /** * ?? * * @param profile */ private void doSelectProfile(LinuxProfile profile) { doClose(); currentProfile = profile; showEditLayout(true); editNickName.setText(profile.getNickName()); editDevicePath.setText(profile.getDevicePath()); editMountPoint.setText(profile.getMountPoint()); editDiskTableFile.setText(profile.getDiskTableFile()); editInitProgram.setText(profile.getInitProgram()); editInitProgramArgs.setText(profile.getInitProgramArgs()); String fsType = profile.getFileSystemType(); editFsType.select(fsType); editMountSd0.setChecked(profile.isMountSdcard0()); editMountSd1.setChecked(profile.isMountSdcard1()); setStatus(STATUS_EDITING); } /** * ? */ private void doCreateNewImage() { Intent i = new Intent(this, CreateImageActivity.class); startActivity(i); } /** * ? */ private void doCreateNewProfile() { LinuxProfile profile = new LinuxProfile(); profile.setNickName("linux_" + UUID.randomUUID().toString().substring(0, 6)); doSelectProfile(profile); } /** * ??? */ private void doClose() { resetEditWidgets(); showEditLayout(false); setStatus(STATUS_NORMAL); currentProfile = null; } /** * ?? * * @param closeAfterSave ???? * @return ??? */ private boolean doSave(boolean closeAfterSave) { if (currentProfile == null) { return false; } if (editNickName.getText().toString().isEmpty()) { String err = getString(R.string.nick_name_cannot_be_null); Snackbar.make(floatingButton, err, Snackbar.LENGTH_SHORT).show(); return false; } if (editDevicePath.getText().toString().isEmpty()) { String err = getString(R.string.device_path_cannot_be_null); Snackbar.make(floatingButton, err, Snackbar.LENGTH_SHORT).show(); return false; } LinuxProfile pro = currentProfile; pro.setNickName(editNickName.getText().toString()); pro.setDevicePath(editDevicePath.getText().toString()); pro.setMountPoint(editMountPoint.getText().toString()); pro.setDiskTableFile(editDiskTableFile.getText().toString()); pro.setInitProgram(editInitProgram.getText().toString()); pro.setInitProgramArgs(editInitProgramArgs.getText().toString()); pro.setFileSystemType((String) editFsType.getSelectedItem()); pro.setMountSdcard0(editMountSd0.isChecked()); pro.setMountSdcard1(editMountSd1.isChecked()); if (!ProfileManager.getInstance().saveProfile(pro)) { Snackbar.make(floatingButton, R.string.save_failed, Snackbar.LENGTH_SHORT).show(); return false; } profileListAdapter.update(pro); Snackbar.make(floatingButton, R.string.save_successfully, Snackbar.LENGTH_SHORT).show(); if (closeAfterSave) { doClose(); } return true; } /** * ??? * * @param profile ?? */ private void doShowOptions(final LinuxProfile profile) { String[] items = getResources().getStringArray(R.array.profile_options); new AlertDialog.Builder(this).setTitle(profile.getNickName()) .setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { // launch case 0: doLaunch(profile); break; // delete case 1: doDelete(profile); break; } } }).setPositiveButton(android.R.string.no, null).show(); } /** * ?? * * @param profile ??? */ private void doLaunch(LinuxProfile profile) { String command = LaunchUtils.createTerminalCommand(this, profile); Intent i = LaunchUtils.createTerminalIntent(profile.getNickName(), command); try { profile.getOmlInterface().onLaunch(this, profile); startActivity(i); profile.getOmlInterface().onPostLaunch(this, profile); } catch (Exception e) { L.e(e); new AlertDialog.Builder(this).setTitle(R.string.launch_field).setMessage(R.string.no_terminal_found) .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { byte[] termBuffer = ResourceUtils.readAssetsFile(MainActivity.this, "terminal"); File saveTo = new File(MainActivity.this.getExternalCacheDir(), "term.apk"); if (!FileUtils.writeFile(saveTo, termBuffer)) { L.e("cannot extract terminal from apk archive!"); } Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.fromFile(saveTo), "application/vnd.android.package-archive"); startActivity(i); } }).setNegativeButton(android.R.string.no, null).show(); } } /** * ???? */ private void doLaunch() { if (!doSave(false)) { new AlertDialog.Builder(this).setTitle(R.string.launch_field) .setPositiveButton(android.R.string.yes, null).show(); return; } doLaunch(currentProfile); } /** * ? * * @param profile ?? */ private void doDelete(final LinuxProfile profile) { new AlertDialog.Builder(this).setTitle(R.string.delete) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ProfileManager.getInstance().deleteProfile(profile); profileListAdapter.remove(profile); } }).setNegativeButton(android.R.string.no, null).show(); } /** * ?? * * @param en ??? */ private void showEditLayout(boolean en) { if (en) { defaultLayout.setVisibility(View.GONE); editLayout.setVisibility(View.VISIBLE); } else { defaultLayout.setVisibility(View.VISIBLE); editLayout.setVisibility(View.GONE); } } /** * ?? */ private void resetEditWidgets() { editNickName.setText(""); editDevicePath.setText(""); editMountPoint.setText(""); editDiskTableFile.setText(""); editInitProgram.setText(""); editInitProgramArgs.setText(""); editFsType.select("ext4"); editMountSd0.setChecked(false); editMountSd1.setChecked(false); } /** * ??() * * @param status ? */ private void setStatus(int status) { this.status = status; switch (status) { case STATUS_NORMAL: floatingButton.setImageResource(R.drawable.ic_add); break; case STATUS_EDITING: floatingButton.setImageResource(R.drawable.ic_close); break; } } /** * ?log?? * * @param msg log? */ private void log(String msg) { logTextView.append(">>> "); logTextView.append(msg); logTextView.append("\n"); logScrollView.fullScroll(ScrollView.FOCUS_DOWN); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_save) { doSave(false); return true; } else if (id == R.id.action_launch) { doLaunch(); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); return true; } if (drawer.isDrawerOpen(GravityCompat.END)) { drawer.closeDrawer(GravityCompat.END); return true; } } return super.onKeyDown(keyCode, event); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != RESULT_OK) { return; } Uri uri = data.getData(); if (uri == null) { return; } String path = FileUtils.getPathFromUri(this, uri); switch (requestCode) { case REQ_FIND_DEVICE_PATH: editDevicePath.setText(path); break; case REQ_FIND_DISK_TABLE: editDiskTableFile.setText(path); break; } super.onActivityResult(requestCode, resultCode, data); } @Override protected void onDestroy() { super.onDestroy(); L.setLogCallback(null); } @Override public void onE(String errorMsg) { log("[ERROR] " + errorMsg); } @Override public void onD(String debugMsg) { log("[DEBUG] " + debugMsg); } @Override public void onI(String infoMsg) { log("[INFO] " + infoMsg); } @Override public void onW(String warnMsg) { log("[WARNING] " + warnMsg); } }