From 4bae12aa5512e4e88e1c25141a325aff7a3da297 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 21 Apr 2016 20:28:01 -0300 Subject: [PATCH 1/7] Embedded GigaGet download manager. First try. --- app/build.gradle | 2 + app/src/main/AndroidManifest.xml | 23 ++ .../newpipe/download/DownloadDialog.java | 53 +-- .../schabi/newpipe/download/MainActivity.java | 280 +++++++++++++++ .../us/shandian/giga/get/DownloadManager.java | 14 + .../giga/get/DownloadManagerImpl.java | 214 +++++++++++ .../us/shandian/giga/get/DownloadMission.java | 229 ++++++++++++ .../shandian/giga/get/DownloadRunnable.java | 174 +++++++++ .../giga/get/DownloadRunnableFallback.java | 74 ++++ .../get/FilteredDownloadManagerWrapper.java | 88 +++++ .../giga/service/DownloadManagerService.java | 186 ++++++++++ .../giga/ui/adapter/MissionAdapter.java | 340 ++++++++++++++++++ .../giga/ui/common/BlockGraphView.java | 84 +++++ .../giga/ui/common/FloatingActionButton.java | 231 ++++++++++++ .../giga/ui/common/ProgressDrawable.java | 58 +++ .../giga/ui/common/ToolbarActivity.java | 26 ++ .../giga/ui/fragment/AllMissionsFragment.java | 13 + .../fragment/DownloadedMissionsFragment.java | 13 + .../fragment/DownloadingMissionsFragment.java | 13 + .../giga/ui/fragment/MissionsFragment.java | 134 +++++++ .../us/shandian/giga/util/CrashHandler.java | 84 +++++ .../java/us/shandian/giga/util/Settings.java | 60 ++++ .../java/us/shandian/giga/util/Utility.java | 334 +++++++++++++++++ .../res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 161 bytes app/src/main/res/drawable-hdpi/grid.png | Bin 0 -> 3039 bytes .../res/drawable-hdpi/ic_add_white_24dp.png | Bin 0 -> 223 bytes .../main/res/drawable-hdpi/ic_menu_more.png | Bin 0 -> 319 bytes app/src/main/res/drawable-hdpi/list.png | Bin 0 -> 3129 bytes .../main/res/drawable-ldrtl-xhdpi/apps.png | Bin 0 -> 28279 bytes .../main/res/drawable-ldrtl-xhdpi/archive.png | Bin 0 -> 26362 bytes .../drawable-ldrtl-xhdpi/drawer_shadow.9.png | Bin 0 -> 174 bytes .../main/res/drawable-ldrtl-xhdpi/excel.png | Bin 0 -> 30001 bytes .../main/res/drawable-ldrtl-xhdpi/grid.png | Bin 0 -> 2960 bytes .../ic_add_white_24dp.png | Bin 0 -> 198 bytes .../res/drawable-ldrtl-xhdpi/ic_menu_more.png | Bin 0 -> 446 bytes .../main/res/drawable-ldrtl-xhdpi/list.png | Bin 0 -> 3006 bytes .../main/res/drawable-ldrtl-xhdpi/music.png | Bin 0 -> 28646 bytes app/src/main/res/drawable-ldrtl-xhdpi/pdf.png | Bin 0 -> 31386 bytes .../res/drawable-ldrtl-xhdpi/powerpoint.png | Bin 0 -> 25507 bytes .../main/res/drawable-ldrtl-xhdpi/unknown.png | Bin 0 -> 23363 bytes .../main/res/drawable-ldrtl-xhdpi/video.png | Bin 0 -> 23722 bytes .../main/res/drawable-ldrtl-xhdpi/word.png | Bin 0 -> 29211 bytes app/src/main/res/drawable-xxhdpi/grid.png | Bin 0 -> 18221 bytes .../res/drawable-xxhdpi/ic_add_white_24dp.png | Bin 0 -> 222 bytes app/src/main/res/drawable-xxhdpi/list.png | Bin 0 -> 18220 bytes app/src/main/res/drawable/action_shadow.xml | 12 + .../main/res/layout/activity_downloader.xml | 18 + app/src/main/res/layout/dialog_url.xml | 111 ++++++ app/src/main/res/layout/mission_item.xml | 81 +++++ .../main/res/layout/mission_item_linear.xml | 83 +++++ app/src/main/res/layout/missions.xml | 12 + app/src/main/res/menu/dialog_url.xml | 10 + app/src/main/res/menu/frag_mission.xml | 11 + app/src/main/res/menu/mission.xml | 37 ++ app/src/main/res/values-v21/styles.xml | 1 + app/src/main/res/values/colors.xml | 22 ++ app/src/main/res/values/strings.xml | 35 ++ app/src/main/res/values/styles.xml | 1 + 58 files changed, 3121 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/download/MainActivity.java create mode 100644 app/src/main/java/us/shandian/giga/get/DownloadManager.java create mode 100755 app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java create mode 100644 app/src/main/java/us/shandian/giga/get/DownloadMission.java create mode 100644 app/src/main/java/us/shandian/giga/get/DownloadRunnable.java create mode 100644 app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java create mode 100644 app/src/main/java/us/shandian/giga/get/FilteredDownloadManagerWrapper.java create mode 100755 app/src/main/java/us/shandian/giga/service/DownloadManagerService.java create mode 100644 app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java create mode 100755 app/src/main/java/us/shandian/giga/ui/common/BlockGraphView.java create mode 100644 app/src/main/java/us/shandian/giga/ui/common/FloatingActionButton.java create mode 100644 app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java create mode 100644 app/src/main/java/us/shandian/giga/ui/common/ToolbarActivity.java create mode 100644 app/src/main/java/us/shandian/giga/ui/fragment/AllMissionsFragment.java create mode 100644 app/src/main/java/us/shandian/giga/ui/fragment/DownloadedMissionsFragment.java create mode 100644 app/src/main/java/us/shandian/giga/ui/fragment/DownloadingMissionsFragment.java create mode 100644 app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java create mode 100644 app/src/main/java/us/shandian/giga/util/CrashHandler.java create mode 100644 app/src/main/java/us/shandian/giga/util/Settings.java create mode 100644 app/src/main/java/us/shandian/giga/util/Utility.java create mode 100644 app/src/main/res/drawable-hdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-hdpi/grid.png create mode 100644 app/src/main/res/drawable-hdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_menu_more.png create mode 100644 app/src/main/res/drawable-hdpi/list.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/apps.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/archive.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/excel.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/grid.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/ic_menu_more.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/list.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/music.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/pdf.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/powerpoint.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/unknown.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/video.png create mode 100644 app/src/main/res/drawable-ldrtl-xhdpi/word.png create mode 100644 app/src/main/res/drawable-xxhdpi/grid.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/list.png create mode 100644 app/src/main/res/drawable/action_shadow.xml create mode 100644 app/src/main/res/layout/activity_downloader.xml create mode 100644 app/src/main/res/layout/dialog_url.xml create mode 100644 app/src/main/res/layout/mission_item.xml create mode 100644 app/src/main/res/layout/mission_item_linear.xml create mode 100644 app/src/main/res/layout/missions.xml create mode 100644 app/src/main/res/menu/dialog_url.xml create mode 100644 app/src/main/res/menu/frag_mission.xml create mode 100644 app/src/main/res/menu/mission.xml diff --git a/app/build.gradle b/app/build.gradle index 0e1552e2d..0e4929f88 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,4 +43,6 @@ dependencies { compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' compile 'com.github.nirhart:parallaxscroll:1.0' compile 'com.google.android.exoplayer:exoplayer:r1.5.5' + compile 'com.google.code.gson:gson:2.3.+' + compile 'com.nononsenseapps:filepicker:2.0.5' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a4ffff035..fb017102b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -125,5 +125,28 @@ android:label="@string/general_error" android:theme="@android:style/Theme.NoDisplay" /> + + + + + + + + + + + + diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 8791f5a3d..c53b4abb1 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -2,9 +2,9 @@ package org.schabi.newpipe.download; import android.Manifest; import android.app.Dialog; -import android.app.DownloadManager; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; @@ -14,7 +14,6 @@ import android.support.v4.app.DialogFragment; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.util.Log; -import android.widget.Toast; import org.schabi.newpipe.App; import org.schabi.newpipe.NewPipeSettings; @@ -152,49 +151,23 @@ public class DownloadDialog extends DialogFragment { private void download(String url, String title, String fileSuffix, File downloadDir, Context context) { - if(!downloadDir.exists()) { - //attempt to create directory - boolean mkdir = downloadDir.mkdirs(); - if(!mkdir && !downloadDir.isDirectory()) { - String message = context.getString(R.string.err_dir_create,downloadDir.toString()); - Log.e(TAG, message); - Toast.makeText(context,message , Toast.LENGTH_LONG).show(); - - return; - } - String message = context.getString(R.string.info_dir_created,downloadDir.toString()); - Log.e(TAG, message); - Toast.makeText(context,message , Toast.LENGTH_LONG).show(); - } - File saveFilePath = new File(downloadDir,createFileName(title) + fileSuffix); long id = 0; - - if (App.isUsingTor()) { - // if using Tor, do not use DownloadManager because the proxy cannot be set - FileDownloader.downloadFile(getContext(), url, saveFilePath, title); - } else { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request( - Uri.parse(url)); - request.setDestinationUri(Uri.fromFile(saveFilePath)); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - - request.setTitle(title); - request.setDescription("'" + url + - "' => '" + saveFilePath + "'"); - request.allowScanningByMediaScanner(); - - try { - id = dm.enqueue(request); - } catch (Exception e) { - e.printStackTrace(); - } - } - Log.i(TAG,"Started downloading '" + url + "' => '" + saveFilePath + "' #" + id); + + if (App.isUsingTor()) { + //if using Tor, do not use DownloadManager because the proxy cannot be set + //we'll see later + FileDownloader.downloadFile(getContext(), url, saveFilePath, title); + } else { + Intent intent = new Intent(getContext(), MainActivity.class); + intent.setAction(MainActivity.INTENT_DOWNLOAD); + intent.setData(Uri.parse(url)); + intent.putExtra("fileName", createFileName(title) + fileSuffix); + startActivity(intent); + } } } diff --git a/app/src/main/java/org/schabi/newpipe/download/MainActivity.java b/app/src/main/java/org/schabi/newpipe/download/MainActivity.java new file mode 100644 index 000000000..72578ea47 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/download/MainActivity.java @@ -0,0 +1,280 @@ +package org.schabi.newpipe.download; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.app.FragmentTransaction; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.schabi.newpipe.R; + +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.service.DownloadManagerService; +import us.shandian.giga.ui.fragment.AllMissionsFragment; +import us.shandian.giga.ui.fragment.MissionsFragment; +import us.shandian.giga.util.CrashHandler; +import us.shandian.giga.util.Utility; + +public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener{ + + public static final String INTENT_DOWNLOAD = "us.shandian.giga.intent.DOWNLOAD"; + + public static final String INTENT_LIST = "us.shandian.giga.intent.LIST"; + + private MissionsFragment mFragment; + private DownloadManager mManager; + private DownloadManagerService.DMBinder mBinder; + + private String mPendingUrl; + private SharedPreferences mPrefs; + + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName p1, IBinder binder) { + mBinder = (DownloadManagerService.DMBinder) binder; + mManager = mBinder.getDownloadManager(); + } + + @Override + public void onServiceDisconnected(ComponentName p1) { + + } + }; + + @Override + @TargetApi(21) + protected void onCreate(Bundle savedInstanceState) { + CrashHandler.init(this); + CrashHandler.register(); + + // Service + Intent i = new Intent(); + i.setClass(this, DownloadManagerService.class); + startService(i); + bindService(i, mConnection, Context.BIND_AUTO_CREATE); + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_downloader); + + + mPrefs = getSharedPreferences("threads", Context.MODE_WORLD_READABLE); + + + // Fragment + getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + updateFragments(); + getWindow().getDecorView().getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + }); + + // Intent + if (getIntent().getAction().equals(INTENT_DOWNLOAD)) { + mPendingUrl = getIntent().getData().toString(); + } + } + + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + if (intent.getAction().equals(INTENT_DOWNLOAD)) { + mPendingUrl = intent.getData().toString(); + } + } + + @Override + protected void onResume() { + super.onResume(); + + if (mPendingUrl != null) { + showUrlDialog(); + mPendingUrl = null; + } + } + + private void updateFragments() { + + mFragment = new AllMissionsFragment(); + + getFragmentManager().beginTransaction() + .replace(R.id.frame, mFragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .commit(); + + } + + private void showUrlDialog() { + // Create the view + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View v = inflater.inflate(R.layout.dialog_url, null); + final EditText text = Utility.findViewById(v, R.id.url); + final EditText name = Utility.findViewById(v, R.id.file_name); + final TextView tCount = Utility.findViewById(v, R.id.threads_count); + final SeekBar threads = Utility.findViewById(v, R.id.threads); + final Toolbar toolbar = Utility.findViewById(v, R.id.toolbar); + final Button fetch = Utility.findViewById(v, R.id.fetch_name); + + threads.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + + @Override + public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) { + tCount.setText(String.valueOf(progress + 1)); + } + + @Override + public void onStartTrackingTouch(SeekBar p1) { + + } + + @Override + public void onStopTrackingTouch(SeekBar p1) { + + } + + }); + + int def = mPrefs.getInt("threads", 4); + threads.setProgress(def - 1); + tCount.setText(String.valueOf(def)); + + if (mPendingUrl != null) { + text.setText(mPendingUrl); + } + + name.setText(getIntent().getStringExtra("fileName")); + + toolbar.setTitle(R.string.add); + toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); + toolbar.inflateMenu(R.menu.dialog_url); + + // Show the dialog + final AlertDialog dialog = new AlertDialog.Builder(this) + .setCancelable(true) + .setView(v) + .create(); + + dialog.show(); + + fetch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + new NameFetcherTask().execute(text, name); + } + }); + + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog.dismiss(); + } + }); + + toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + if (item.getItemId() == R.id.okay) { + String url = text.getText().toString().trim(); + String fName = name.getText().toString().trim(); + + File f = new File(mManager.getLocation() + "/" + fName); + + if (f.exists()) { + Toast.makeText(MainActivity.this, R.string.msg_exists, Toast.LENGTH_SHORT).show(); + } else if (!checkURL(url)) { + Toast.makeText(MainActivity.this, R.string.msg_url_malform, Toast.LENGTH_SHORT).show(); + } else { + + while (mBinder == null); + + int res = mManager.startMission(url, fName, threads.getProgress() + 1); + mBinder.onMissionAdded(mManager.getMission(res)); + mFragment.notifyChange(); + + mPrefs.edit().putInt("threads", threads.getProgress() + 1).commit(); + mPendingUrl = null; + dialog.dismiss(); + } + + return true; + } else { + return false; + } + } + }); + + } + + private boolean checkURL(String url) { + try { + URL u = new URL(url); + u.openConnection(); + return true; + } catch (MalformedURLException e) { + return false; + } catch (IOException e) { + return false; + } + } + + private class NameFetcherTask extends AsyncTask { + + @Override + protected Object[] doInBackground(View[] params) { + try { + URL url = new URL(((EditText) params[0]).getText().toString()); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + String header = conn.getHeaderField("Content-Disposition"); + + if (header != null && header.indexOf("=") != -1) { + return new Object[]{params[1], header.split("=")[1].replace("\"", "")}; + } + } catch (Exception e) { + + } + return null; + } + + @Override + protected void onPostExecute(Object[] result) { + super.onPostExecute(result); + + if (result != null) { + ((EditText) result[0]).setText(result[1].toString()); + } + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + + } + +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadManager.java b/app/src/main/java/us/shandian/giga/get/DownloadManager.java new file mode 100644 index 000000000..e1ff8e297 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/DownloadManager.java @@ -0,0 +1,14 @@ +package us.shandian.giga.get; + +public interface DownloadManager +{ + public static final int BLOCK_SIZE = 512 * 1024; + + public int startMission(String url, String name, int threads); + public void resumeMission(int id); + public void pauseMission(int id); + public void deleteMission(int id); + public DownloadMission getMission(int id); + public int getCount(); + public String getLocation(); +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java new file mode 100755 index 000000000..b7067c1a4 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/DownloadManagerImpl.java @@ -0,0 +1,214 @@ +package us.shandian.giga.get; + +import android.content.Context; +import android.util.Log; + +import com.google.gson.Gson; + +import java.io.File; +import java.io.RandomAccessFile; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; + +import us.shandian.giga.util.Utility; +import static org.schabi.newpipe.BuildConfig.DEBUG; + +public class DownloadManagerImpl implements DownloadManager +{ + private static final String TAG = DownloadManagerImpl.class.getSimpleName(); + + private Context mContext; + private String mLocation; + protected ArrayList mMissions = new ArrayList(); + + public DownloadManagerImpl(Context context, String location) { + mContext = context; + mLocation = location; + loadMissions(); + } + + @Override + public int startMission(String url, String name, int threads) { + DownloadMission mission = new DownloadMission(); + mission.url = url; + mission.name = name; + mission.location = mLocation; + mission.timestamp = System.currentTimeMillis(); + mission.threadCount = threads; + new Initializer(mContext, mission).start(); + return insertMission(mission); + } + + @Override + public void resumeMission(int i) { + DownloadMission d = getMission(i); + if (!d.running && d.errCode == -1) { + d.start(); + } + } + + @Override + public void pauseMission(int i) { + DownloadMission d = getMission(i); + if (d.running) { + d.pause(); + } + } + + @Override + public void deleteMission(int i) { + getMission(i).delete(); + mMissions.remove(i); + } + + private void loadMissions() { + File f = new File(mLocation); + + if (f.exists() && f.isDirectory()) { + File[] subs = f.listFiles(); + + for (File sub : subs) { + if (sub.isDirectory()) { + continue; + } + + if (sub.getName().endsWith(".giga")) { + String str = Utility.readFromFile(sub.getAbsolutePath()); + if (str != null && !str.trim().equals("")) { + + if (DEBUG) { + Log.d(TAG, "loading mission " + sub.getName()); + Log.d(TAG, str); + } + + DownloadMission mis = new Gson().fromJson(str, DownloadMission.class); + + if (mis.finished) { + sub.delete(); + continue; + } + + mis.running = false; + mis.recovered = true; + insertMission(mis); + } + } else if (!sub.getName().startsWith(".") && !new File(sub.getPath() + ".giga").exists()) { + // Add a dummy mission for downloaded files + DownloadMission mis = new DownloadMission(); + mis.length = sub.length(); + mis.done = mis.length; + mis.finished = true; + mis.running = false; + mis.name = sub.getName(); + mis.location = mLocation; + mis.timestamp = sub.lastModified(); + insertMission(mis); + } + } + } + } + + @Override + public DownloadMission getMission(int i) { + return mMissions.get(i); + } + + @Override + public int getCount() { + return mMissions.size(); + } + + private int insertMission(DownloadMission mission) { + int i = -1; + + DownloadMission m = null; + + if (mMissions.size() > 0) { + do { + m = mMissions.get(++i); + } while (m.timestamp > mission.timestamp && i < mMissions.size() - 1); + + //if (i > 0) i--; + } else { + i = 0; + } + + mMissions.add(i, mission); + + return i; + } + + @Override + public String getLocation() { + return mLocation; + } + + private class Initializer extends Thread { + private Context context; + private DownloadMission mission; + + public Initializer(Context context, DownloadMission mission) { + this.context = context; + this.mission = mission; + } + + @Override + public void run() { + try { + URL url = new URL(mission.url); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + mission.length = conn.getContentLength(); + + if (mission.length <= 0) { + mission.errCode = DownloadMission.ERROR_SERVER_UNSUPPORTED; + //mission.notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED); + return; + } + + // Open again + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Range", "bytes=" + (mission.length - 10) + "-" + mission.length); + + if (conn.getResponseCode() != 206) { + // Fallback to single thread if no partial content support + mission.fallback = true; + + if (DEBUG) { + Log.d(TAG, "falling back"); + } + } + + if (DEBUG) { + Log.d(TAG, "response = " + conn.getResponseCode()); + } + + mission.blocks = mission.length / BLOCK_SIZE; + + if (mission.threadCount > mission.blocks) { + mission.threadCount = (int) mission.blocks; + } + + if (mission.threadCount <= 0) { + mission.threadCount = 1; + } + + if (mission.blocks * BLOCK_SIZE < mission.length) { + mission.blocks++; + } + + + new File(mission.location).mkdirs(); + new File(mission.location + "/" + mission.name).createNewFile(); + RandomAccessFile af = new RandomAccessFile(mission.location + "/" + mission.name, "rw"); + af.setLength(mission.length); + af.close(); + + mission.start(); + } catch (Exception e) { + // TODO Notify + throw new RuntimeException(e); + } + } + } +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadMission.java b/app/src/main/java/us/shandian/giga/get/DownloadMission.java new file mode 100644 index 000000000..bbcee7e94 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/DownloadMission.java @@ -0,0 +1,229 @@ +package us.shandian.giga.get; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.google.gson.Gson; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.HashMap; + +import us.shandian.giga.util.Utility; +import static org.schabi.newpipe.BuildConfig.DEBUG; + +public class DownloadMission +{ + private static final String TAG = DownloadMission.class.getSimpleName(); + + public static interface MissionListener { + HashMap handlerStore = new HashMap<>(); + + public void onProgressUpdate(long done, long total); + public void onFinish(); + public void onError(int errCode); + } + + public static final int ERROR_SERVER_UNSUPPORTED = 206; + public static final int ERROR_UNKNOWN = 233; + + public String name = ""; + public String url = ""; + public String location = ""; + public long blocks = 0; + public long length = 0; + public long done = 0; + public int threadCount = 3; + public int finishCount = 0; + public ArrayList threadPositions = new ArrayList(); + public HashMap blockState = new HashMap(); + public boolean running = false; + public boolean finished = false; + public boolean fallback = false; + public int errCode = -1; + public long timestamp = 0; + + public transient boolean recovered = false; + + private transient ArrayList> mListeners = new ArrayList>(); + private transient boolean mWritingToFile = false; + + public boolean isBlockPreserved(long block) { + return blockState.containsKey(block) ? blockState.get(block) : false; + } + + public void preserveBlock(long block) { + synchronized (blockState) { + blockState.put(block, true); + } + } + + public void setPosition(int id, long position) { + threadPositions.set(id, position); + } + + public long getPosition(int id) { + return threadPositions.get(id); + } + + public synchronized void notifyProgress(long deltaLen) { + if (!running) return; + + if (recovered) { + recovered = false; + } + + done += deltaLen; + + if (done > length) { + done = length; + } + + if (done != length) { + writeThisToFile(); + } + + for (WeakReference ref: mListeners) { + final MissionListener listener = ref.get(); + if (listener != null) { + MissionListener.handlerStore.get(listener).post(new Runnable() { + @Override + public void run() { + listener.onProgressUpdate(done, length); + } + }); + } + } + } + + public synchronized void notifyFinished() { + if (errCode > 0) return; + + finishCount++; + + if (finishCount == threadCount) { + onFinish(); + } + } + + private void onFinish() { + if (errCode > 0) return; + + if (DEBUG) { + Log.d(TAG, "onFinish"); + } + + running = false; + finished = true; + + deleteThisFromFile(); + + for (WeakReference ref : mListeners) { + final MissionListener listener = ref.get(); + if (listener != null) { + MissionListener.handlerStore.get(listener).post(new Runnable() { + @Override + public void run() { + listener.onFinish(); + } + }); + } + } + } + + public synchronized void notifyError(int err) { + errCode = err; + + writeThisToFile(); + + for (WeakReference ref : mListeners) { + final MissionListener listener = ref.get(); + MissionListener.handlerStore.get(listener).post(new Runnable() { + @Override + public void run() { + listener.onError(errCode); + } + }); + } + } + + public synchronized void addListener(MissionListener listener) { + Handler handler = new Handler(Looper.getMainLooper()); + MissionListener.handlerStore.put(listener, handler); + mListeners.add(new WeakReference(listener)); + } + + public synchronized void removeListener(MissionListener listener) { + for (Iterator> iterator = mListeners.iterator(); + iterator.hasNext(); ) { + WeakReference weakRef = iterator.next(); + if (listener!=null && listener == weakRef.get()) + { + iterator.remove(); + } + } + } + + public void start() { + if (!running && !finished) { + running = true; + + if (!fallback) { + for (int i = 0; i < threadCount; i++) { + if (threadPositions.size() <= i && !recovered) { + threadPositions.add((long) i); + } + new Thread(new DownloadRunnable(this, i)).start(); + } + } else { + // In fallback mode, resuming is not supported. + threadCount = 1; + done = 0; + blocks = 0; + new Thread(new DownloadRunnableFallback(this)).start(); + } + } + } + + public void pause() { + if (running) { + running = false; + recovered = true; + + // TODO: Notify & Write state to info file + // if (err) + } + } + + public void delete() { + deleteThisFromFile(); + new File(location + "/" + name).delete(); + } + + public void writeThisToFile() { + if (!mWritingToFile) { + mWritingToFile = true; + new Thread() { + @Override + public void run() { + doWriteThisToFile(); + mWritingToFile = false; + } + }.start(); + } + } + + private void doWriteThisToFile() { + synchronized (blockState) { + Utility.writeToFile(location + "/" + name + ".giga", new Gson().toJson(this)); + } + } + + private void deleteThisFromFile() { + new File(location + "/" + name + ".giga").delete(); + } +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java b/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java new file mode 100644 index 000000000..48990bde6 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/DownloadRunnable.java @@ -0,0 +1,174 @@ +package us.shandian.giga.get; + +import android.os.Handler; +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.RandomAccessFile; +import java.net.HttpURLConnection; +import java.net.URL; + +import static org.schabi.newpipe.BuildConfig.DEBUG; + +public class DownloadRunnable implements Runnable +{ + private static final String TAG = DownloadRunnable.class.getSimpleName(); + + private DownloadMission mMission; + private int mId; + + public DownloadRunnable(DownloadMission mission, int id) { + mMission = mission; + mId = id; + } + + @Override + public void run() { + boolean retry = mMission.recovered; + long position = mMission.getPosition(mId); + + if (DEBUG) { + Log.d(TAG, mId + ":default pos " + position); + Log.d(TAG, mId + ":recovered: " + mMission.recovered); + } + + while (mMission.errCode == -1 && mMission.running && position < mMission.blocks) { + + if (Thread.currentThread().isInterrupted()) { + mMission.pause(); + return; + } + + if (DEBUG && retry) { + Log.d(TAG, mId + ":retry is true. Resuming at " + position); + } + + // Wait for an unblocked position + while (!retry && position < mMission.blocks && mMission.isBlockPreserved(position)) { + + if (DEBUG) { + Log.d(TAG, mId + ":position " + position + " preserved, passing"); + } + + position++; + } + + retry = false; + + if (position >= mMission.blocks) { + break; + } + + if (DEBUG) { + Log.d(TAG, mId + ":preserving position " + position); + } + + mMission.preserveBlock(position); + mMission.setPosition(mId, position); + + long start = position * DownloadManager.BLOCK_SIZE; + long end = start + DownloadManager.BLOCK_SIZE - 1; + + if (end >= mMission.length) { + end = mMission.length - 1; + } + + HttpURLConnection conn = null; + + int total = 0; + + try { + URL url = new URL(mMission.url); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestProperty("Range", "bytes=" + start + "-" + end); + + if (DEBUG) { + Log.d(TAG, mId + ":" + conn.getRequestProperty("Range")); + Log.d(TAG, mId + ":Content-Length=" + conn.getContentLength() + " Code:" + conn.getResponseCode()); + } + + // A server may be ignoring the range requet + if (conn.getResponseCode() != 206) { + mMission.errCode = DownloadMission.ERROR_SERVER_UNSUPPORTED; + notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED); + + if (DEBUG) { + Log.e(TAG, mId + ":Unsupported " + conn.getResponseCode()); + } + + break; + } + + RandomAccessFile f = new RandomAccessFile(mMission.location + "/" + mMission.name, "rw"); + f.seek(start); + BufferedInputStream ipt = new BufferedInputStream(conn.getInputStream()); + byte[] buf = new byte[512]; + + while (start < end && mMission.running) { + int len = ipt.read(buf, 0, 512); + + if (len == -1) { + break; + } else { + start += len; + total += len; + f.write(buf, 0, len); + notifyProgress(len); + } + } + + if (DEBUG && mMission.running) { + Log.d(TAG, mId + ":position " + position + " finished, total length " + total); + } + + f.close(); + ipt.close(); + + // TODO We should save progress for each thread + } catch (Exception e) { + // TODO Retry count limit & notify error + retry = true; + + notifyProgress(-total); + + if (DEBUG) { + Log.d(TAG, mId + ":position " + position + " retrying"); + } + } + } + + if (DEBUG) { + Log.d(TAG, "thread " + mId + " exited main loop"); + } + + if (mMission.errCode == -1 && mMission.running) { + if (DEBUG) { + Log.d(TAG, "no error has happened, notifying"); + } + notifyFinished(); + } + + if (DEBUG && !mMission.running) { + Log.d(TAG, "The mission has been paused. Passing."); + } + } + + private void notifyProgress(final long len) { + synchronized (mMission) { + mMission.notifyProgress(len); + } + } + + private void notifyError(final int err) { + synchronized (mMission) { + mMission.notifyError(err); + mMission.pause(); + } + } + + private void notifyFinished() { + synchronized (mMission) { + mMission.notifyFinished(); + } + } +} diff --git a/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java new file mode 100644 index 000000000..50bdce858 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java @@ -0,0 +1,74 @@ +package us.shandian.giga.get; + +import java.io.BufferedInputStream; +import java.io.RandomAccessFile; +import java.net.HttpURLConnection; +import java.net.URL; + +// Single-threaded fallback mode +public class DownloadRunnableFallback implements Runnable +{ + private DownloadMission mMission; + //private int mId; + + public DownloadRunnableFallback(DownloadMission mission) { + //mId = id; + mMission = mission; + } + + @Override + public void run() { + try { + URL url = new URL(mMission.url); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + if (conn.getResponseCode() != 200 && conn.getResponseCode() != 206) { + notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED); + } else { + RandomAccessFile f = new RandomAccessFile(mMission.location + "/" + mMission.name, "rw"); + f.seek(0); + BufferedInputStream ipt = new BufferedInputStream(conn.getInputStream()); + byte[] buf = new byte[512]; + int len = 0; + + while ((len = ipt.read(buf, 0, 512)) != -1 && mMission.running) { + f.write(buf, 0, len); + notifyProgress(len); + + if (Thread.currentThread().interrupted()) { + break; + } + + } + + f.close(); + ipt.close(); + } + } catch (Exception e) { + notifyError(DownloadMission.ERROR_UNKNOWN); + } + + if (mMission.errCode == -1 && mMission.running) { + notifyFinished(); + } + } + + private void notifyProgress(final long len) { + synchronized (mMission) { + mMission.notifyProgress(len); + } + } + + private void notifyError(final int err) { + synchronized (mMission) { + mMission.notifyError(err); + mMission.pause(); + } + } + + private void notifyFinished() { + synchronized (mMission) { + mMission.notifyFinished(); + } + } +} diff --git a/app/src/main/java/us/shandian/giga/get/FilteredDownloadManagerWrapper.java b/app/src/main/java/us/shandian/giga/get/FilteredDownloadManagerWrapper.java new file mode 100644 index 000000000..c417def15 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/get/FilteredDownloadManagerWrapper.java @@ -0,0 +1,88 @@ +package us.shandian.giga.get; + +import android.content.Context; + +import java.util.Map.Entry; +import java.util.HashMap; + +public class FilteredDownloadManagerWrapper implements DownloadManager +{ + + private boolean mDownloaded = false; // T=Filter downloaded files; F=Filter downloading files + private DownloadManager mManager; + private HashMap mElementsMap = new HashMap(); + + public FilteredDownloadManagerWrapper(DownloadManager manager, boolean filterDownloaded) { + mManager = manager; + mDownloaded = filterDownloaded; + refreshMap(); + } + + private void refreshMap() { + mElementsMap.clear(); + + int size = 0; + for (int i = 0; i < mManager.getCount(); i++) { + if (mManager.getMission(i).finished == mDownloaded) { + mElementsMap.put(size++, i); + } + } + } + + private int toRealPosition(int pos) { + if (mElementsMap.containsKey(pos)) { + return mElementsMap.get(pos); + } else { + return -1; + } + } + + private int toFakePosition(int pos) { + for (Entry entry : mElementsMap.entrySet()) { + if (entry.getValue() == pos) { + return entry.getKey(); + } + } + + return -1; + } + + @Override + public int startMission(String url, String name, int threads) { + int ret = mManager.startMission(url, name, threads); + refreshMap(); + return toFakePosition(ret); + } + + @Override + public void resumeMission(int id) { + mManager.resumeMission(toRealPosition(id)); + } + + @Override + public void pauseMission(int id) { + mManager.pauseMission(toRealPosition(id)); + } + + @Override + public void deleteMission(int id) { + mManager.deleteMission(toRealPosition(id)); + } + + @Override + public DownloadMission getMission(int id) { + return mManager.getMission(toRealPosition(id)); + } + + + @Override + public int getCount() { + return mElementsMap.size(); + } + + @Override + public String getLocation() { + return mManager.getLocation(); + } + +} diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java new file mode 100755 index 000000000..52be503a6 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java @@ -0,0 +1,186 @@ +package us.shandian.giga.service; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Message; +import android.support.v4.app.NotificationCompat.Builder; +import android.util.Log; + +import org.schabi.newpipe.R; +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.get.DownloadManagerImpl; +import us.shandian.giga.get.DownloadMission; +import org.schabi.newpipe.download.MainActivity; +import us.shandian.giga.util.Settings; +import static org.schabi.newpipe.BuildConfig.DEBUG; + +public class DownloadManagerService extends Service implements DownloadMission.MissionListener +{ + + private static final String TAG = DownloadManagerService.class.getSimpleName(); + + private DMBinder mBinder; + private DownloadManager mManager; + private Notification mNotification; + private Handler mHandler; + private long mLastTimeStamp = System.currentTimeMillis(); + + @Override + public void onCreate() { + super.onCreate(); + + if (DEBUG) { + Log.d(TAG, "onCreate"); + } + + mBinder = new DMBinder(); + if (mManager == null) { + String path = Settings.getInstance(this).getString(Settings.DOWNLOAD_DIRECTORY, Settings.DEFAULT_PATH); + mManager = new DownloadManagerImpl(this, path); + if (DEBUG) { + Log.d(TAG, "mManager == null"); + Log.d(TAG, "Download directory: " + path); + } + } + + Intent i = new Intent(); + i.setAction(Intent.ACTION_MAIN); + i.setClass(this, MainActivity.class); + + Drawable icon = this.getResources().getDrawable(R.mipmap.ic_launcher); + + Builder builder = new Builder(this) + .setContentIntent(PendingIntent.getActivity(this, 0, i, 0)) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setLargeIcon(((BitmapDrawable) icon).getBitmap()) + .setContentTitle(getString(R.string.msg_running)) + .setContentText(getString(R.string.msg_running_detail)); + + PendingIntent pendingIntent = + PendingIntent.getActivity( + this, + 0, + new Intent(this, MainActivity.class) + .setAction(MainActivity.INTENT_LIST), + PendingIntent.FLAG_UPDATE_CURRENT + ); + + builder.setContentIntent(pendingIntent); + + mNotification = builder.build(); + + HandlerThread thread = new HandlerThread("ServiceMessenger"); + thread.start(); + + mHandler = new Handler(thread.getLooper()) { + @Override + public void handleMessage(Message msg) { + if (msg.what == 0) { + int runningCount = 0; + + for (int i = 0; i < mManager.getCount(); i++) { + if (mManager.getMission(i).running) { + runningCount++; + } + } + + updateState(runningCount); + } + } + }; + + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (DEBUG) { + Log.d(TAG, "Starting"); + } + + return START_NOT_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (DEBUG) { + Log.d(TAG, "Destroying"); + } + + for (int i = 0; i < mManager.getCount(); i++) { + mManager.pauseMission(i); + } + + stopForeground(true); + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + + @Override + public void onProgressUpdate(long done, long total) { + + long now = System.currentTimeMillis(); + + long delta = now - mLastTimeStamp; + + if (delta > 2000) { + postUpdateMessage(); + mLastTimeStamp = now; + } + } + + @Override + public void onFinish() { + postUpdateMessage(); + } + + @Override + public void onError(int errCode) { + postUpdateMessage(); + } + + private void postUpdateMessage() { + mHandler.sendEmptyMessage(0); + } + + private void updateState(int runningCount) { + if (runningCount == 0) { + stopForeground(true); + } else { + startForeground(1000, mNotification); + } + } + + + // Wrapper of DownloadManager + public class DMBinder extends Binder { + public DownloadManager getDownloadManager() { + return mManager; + } + + public void onMissionAdded(DownloadMission mission) { + mission.addListener(DownloadManagerService.this); + postUpdateMessage(); + } + + public void onMissionRemoved(DownloadMission mission) { + mission.removeListener(DownloadManagerService.this); + postUpdateMessage(); + } + + } + +} diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java new file mode 100644 index 000000000..4fdbf4f2a --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -0,0 +1,340 @@ +package us.shandian.giga.ui.adapter; + +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.MimeTypeMap; +import android.widget.ImageView; +import android.widget.PopupMenu; +import android.widget.TextView; + +import android.support.v7.widget.RecyclerView; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.schabi.newpipe.R; +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.get.DownloadMission; +import us.shandian.giga.service.DownloadManagerService; +import us.shandian.giga.ui.common.ProgressDrawable; +import us.shandian.giga.util.Utility; + +public class MissionAdapter extends RecyclerView.Adapter +{ + private static final Map ALGORITHMS = new HashMap<>(); + + static { + ALGORITHMS.put(R.id.md5, "MD5"); + ALGORITHMS.put(R.id.sha1, "SHA1"); + } + + private Context mContext; + private LayoutInflater mInflater; + private DownloadManager mManager; + private DownloadManagerService.DMBinder mBinder; + private int mLayout; + + public MissionAdapter(Context context, DownloadManagerService.DMBinder binder, DownloadManager manager, boolean isLinear) { + mContext = context; + mManager = manager; + mBinder = binder; + + mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + mLayout = isLinear ? R.layout.mission_item_linear : R.layout.mission_item; + } + + @Override + public MissionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + final ViewHolder h = new ViewHolder(mInflater.inflate(mLayout, parent, false)); + + h.menu.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + buildPopup(h); + } + }); + + /*h.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDetail(h); + } + });*/ + + return h; + } + + @Override + public void onViewRecycled(MissionAdapter.ViewHolder h) { + super.onViewRecycled(h); + h.mission.removeListener(h.observer); + h.mission = null; + h.observer = null; + h.progress = null; + h.position = -1; + h.lastTimeStamp = -1; + h.lastDone = -1; + h.colorId = 0; + } + + @Override + public void onBindViewHolder(MissionAdapter.ViewHolder h, int pos) { + DownloadMission ms = mManager.getMission(pos); + h.mission = ms; + h.position = pos; + + Utility.FileType type = Utility.getFileType(ms.name); + + //h.icon.setImageResource(Utility.getIconForFileType(type)); + h.name.setText(ms.name); + h.size.setText(Utility.formatBytes(ms.length)); + + h.progress = new ProgressDrawable(mContext, Utility.getBackgroundForFileType(type), Utility.getForegroundForFileType(type)); + h.bkg.setBackgroundDrawable(h.progress); + + h.observer = new MissionObserver(this, h); + ms.addListener(h.observer); + + updateProgress(h); + } + + @Override + public int getItemCount() { + return mManager.getCount(); + } + + @Override + public long getItemId(int position) { + return position; + } + + private void updateProgress(ViewHolder h) { + updateProgress(h, false); + } + + private void updateProgress(ViewHolder h, boolean finished) { + if (h.mission == null) return; + + long now = System.currentTimeMillis(); + + if (h.lastTimeStamp == -1) { + h.lastTimeStamp = now; + } + + if (h.lastDone == -1) { + h.lastDone = h.mission.done; + } + + long deltaTime = now - h.lastTimeStamp; + long deltaDone = h.mission.done - h.lastDone; + + if (deltaTime == 0 || deltaTime > 1000 || finished) { + if (h.mission.errCode > 0) { + h.status.setText(R.string.msg_error); + } else { + float progress = (float) h.mission.done / h.mission.length; + h.status.setText(String.format("%.2f%%", progress * 100)); + h.progress.setProgress(progress); + + } + } + + if (deltaTime > 1000 && deltaDone > 0) { + float speed = (float) deltaDone / deltaTime; + String speedStr = Utility.formatSpeed(speed * 1000); + String sizeStr = Utility.formatBytes(h.mission.length); + + h.size.setText(sizeStr + " " + speedStr); + + h.lastTimeStamp = now; + h.lastDone = h.mission.done; + } + } + + + private void buildPopup(final ViewHolder h) { + PopupMenu popup = new PopupMenu(mContext, h.menu); + popup.inflate(R.menu.mission); + + Menu menu = popup.getMenu(); + MenuItem start = menu.findItem(R.id.start); + MenuItem pause = menu.findItem(R.id.pause); + MenuItem view = menu.findItem(R.id.view); + MenuItem delete = menu.findItem(R.id.delete); + MenuItem checksum = menu.findItem(R.id.checksum); + + // Set to false first + start.setVisible(false); + pause.setVisible(false); + view.setVisible(false); + delete.setVisible(false); + checksum.setVisible(false); + + if (!h.mission.finished) { + if (!h.mission.running) { + if (h.mission.errCode == -1) { + start.setVisible(true); + } + + delete.setVisible(true); + } else { + pause.setVisible(true); + } + } else { + view.setVisible(true); + delete.setVisible(true); + checksum.setVisible(true); + } + + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + int id = item.getItemId(); + switch (id) { + case R.id.start: + mManager.resumeMission(h.position); + mBinder.onMissionAdded(mManager.getMission(h.position)); + return true; + case R.id.pause: + mManager.pauseMission(h.position); + mBinder.onMissionRemoved(mManager.getMission(h.position)); + h.lastTimeStamp = -1; + h.lastDone = -1; + return true; + case R.id.view: + Intent i = new Intent(); + i.setAction(Intent.ACTION_VIEW); + File f = new File(h.mission.location + "/" + h.mission.name); + String ext = Utility.getFileExt(h.mission.name); + + if (ext == null) return false; + + String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.substring(1)); + + if (f.exists()) { + i.setDataAndType(Uri.fromFile(f), mime); + + try { + mContext.startActivity(i); + } catch (Exception e) { + + } + } + + return true; + case R.id.delete: + mManager.deleteMission(h.position); + notifyDataSetChanged(); + return true; + case R.id.md5: + case R.id.sha1: + DownloadMission mission = mManager.getMission(h.position); + new ChecksumTask().execute(mission.location + "/" + mission.name, ALGORITHMS.get(id)); + return true; + default: + return false; + } + } + }); + + popup.show(); + } + + private class ChecksumTask extends AsyncTask { + ProgressDialog prog; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + // Create dialog + prog = new ProgressDialog(mContext); + prog.setCancelable(false); + prog.setMessage(mContext.getString(R.string.msg_wait)); + prog.show(); + } + + @Override + protected String doInBackground(String... params) { + return Utility.checksum(params[0], params[1]); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + prog.dismiss(); + Utility.copyToClipboard(mContext, result); + } + } + + static class ViewHolder extends RecyclerView.ViewHolder { + public DownloadMission mission; + public int position; + + public TextView status; + public ImageView icon; + public TextView name; + public TextView size; + public View bkg; + public ImageView menu; + public ProgressDrawable progress; + public MissionObserver observer; + + public long lastTimeStamp = -1; + public long lastDone = -1; + public int colorId = 0; + + public ViewHolder(View v) { + super(v); + + status = Utility.findViewById(v, R.id.item_status); + icon = Utility.findViewById(v, R.id.item_icon); + name = Utility.findViewById(v, R.id.item_name); + size = Utility.findViewById(v, R.id.item_size); + bkg = Utility.findViewById(v, R.id.item_bkg); + menu = Utility.findViewById(v, R.id.item_more); + } + } + + static class MissionObserver implements DownloadMission.MissionListener { + private MissionAdapter mAdapter; + private ViewHolder mHolder; + + public MissionObserver(MissionAdapter adapter, ViewHolder holder) { + mAdapter = adapter; + mHolder = holder; + } + + @Override + public void onProgressUpdate(long done, long total) { + mAdapter.updateProgress(mHolder); + } + + @Override + public void onFinish() { + //mAdapter.mManager.deleteMission(mHolder.position); + // TODO Notification + //mAdapter.notifyDataSetChanged(); + if (mHolder.mission != null) { + mHolder.size.setText(Utility.formatBytes(mHolder.mission.length)); + mAdapter.updateProgress(mHolder, true); + } + } + + @Override + public void onError(int errCode) { + mAdapter.updateProgress(mHolder); + } + + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/common/BlockGraphView.java b/app/src/main/java/us/shandian/giga/ui/common/BlockGraphView.java new file mode 100755 index 000000000..9e2706678 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/common/BlockGraphView.java @@ -0,0 +1,84 @@ +package us.shandian.giga.ui.common; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +import org.schabi.newpipe.R; +import us.shandian.giga.get.DownloadMission; + +public class BlockGraphView extends View +{ + private static int BLOCKS_PER_LINE = 15; + + private int mForeground, mBackground; + private int mBlockSize, mLineCount; + private DownloadMission mMission; + + public BlockGraphView(Context context) { + this(context, null); + } + + public BlockGraphView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BlockGraphView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + try { + TypedArray array = context.obtainStyledAttributes(R.styleable.AppCompatTheme); + mBackground = array.getColor(R.styleable.AppCompatTheme_colorPrimary, 0); + mForeground = array.getColor(R.styleable.AppCompatTheme_colorPrimaryDark, 0); + array.recycle(); + } catch (Exception e) { + + } + } + + public void setMission(DownloadMission mission) { + mMission = mission; + setWillNotDraw(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + mBlockSize = width / BLOCKS_PER_LINE - 1; + mLineCount = (int) Math.ceil((double) mMission.blocks / BLOCKS_PER_LINE); + int height = mLineCount * (mBlockSize + 1); + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + Paint p = new Paint(); + p.setFlags(Paint.ANTI_ALIAS_FLAG); + + for (int i = 0; i < mLineCount; i++) { + for (int j = 0; j < BLOCKS_PER_LINE; j++) { + long pos = i * BLOCKS_PER_LINE + j; + if (pos >= mMission.blocks) { + break; + } + + if (mMission.isBlockPreserved(pos)) { + p.setColor(mForeground); + } else { + p.setColor(mBackground); + } + + int left = (mBlockSize + 1) * j; + int right = left + mBlockSize; + int top = (mBlockSize + 1) * i; + int bottom = top + mBlockSize; + canvas.drawRect(left, top, right, bottom, p); + } + } + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/common/FloatingActionButton.java b/app/src/main/java/us/shandian/giga/ui/common/FloatingActionButton.java new file mode 100644 index 000000000..424ce388a --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/common/FloatingActionButton.java @@ -0,0 +1,231 @@ +package us.shandian.giga.ui.common; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; + +/* + * From GitHub Gist: https://gist.github.com/Jogan/9def6110edf3247825c9 + */ +public class FloatingActionButton extends View implements Animator.AnimatorListener { + + final static OvershootInterpolator overshootInterpolator = new OvershootInterpolator(); + final static AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator(); + + Context context; + Paint mButtonPaint; + Paint mDrawablePaint; + Bitmap mBitmap; + boolean mHidden = false; + + public FloatingActionButton(Context context) { + super(context); + this.context = context; + init(Color.WHITE); + } + + public void setFloatingActionButtonColor(int FloatingActionButtonColor) { + init(FloatingActionButtonColor); + } + + public void setFloatingActionButtonDrawable(Drawable FloatingActionButtonDrawable) { + mBitmap = ((BitmapDrawable) FloatingActionButtonDrawable).getBitmap(); + invalidate(); + } + + public void init(int FloatingActionButtonColor) { + setWillNotDraw(false); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + + mButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mButtonPaint.setColor(FloatingActionButtonColor); + mButtonPaint.setStyle(Paint.Style.FILL); + mButtonPaint.setShadowLayer(10.0f, 0.0f, 3.5f, Color.argb(100, 0, 0, 0)); + mDrawablePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + setClickable(true); + canvas.drawCircle(getPaddingLeft() + getRealWidth() / 2, + getPaddingTop() + getRealHeight() / 2, + (float) getRealWidth() / 2.6f, mButtonPaint); + canvas.drawBitmap(mBitmap, getPaddingLeft() + (getRealWidth() - mBitmap.getWidth()) / 2, + getPaddingTop() + (getRealHeight() - mBitmap.getHeight()) / 2, mDrawablePaint); + } + + private int getRealWidth() { + return getWidth() - getPaddingLeft() - getPaddingRight(); + } + + private int getRealHeight() { + return getHeight() - getPaddingTop() - getPaddingBottom(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + setAlpha(1.0f); + } else if (event.getAction() == MotionEvent.ACTION_DOWN) { + setAlpha(0.6f); + } + return super.onTouchEvent(event); + } + + @Override + public void onAnimationCancel(Animator anim) { + + } + + @Override + public void onAnimationEnd(Animator anim) { + if (mHidden) { + setVisibility(View.GONE); + } + } + + @Override + public void onAnimationRepeat(Animator anim) { + + } + + @Override + public void onAnimationStart(Animator anim) { + + } + + + public void hideFloatingActionButton() { + if (!mHidden) { + ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 1, 0); + ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 1, 0); + AnimatorSet animSetXY = new AnimatorSet(); + animSetXY.playTogether(scaleX, scaleY); + animSetXY.setInterpolator(accelerateInterpolator); + animSetXY.setDuration(100); + animSetXY.start(); + animSetXY.addListener(this); + mHidden = true; + } + } + + public void showFloatingActionButton() { + if (mHidden) { + setVisibility(View.VISIBLE); + ObjectAnimator scaleX = ObjectAnimator.ofFloat(this, "scaleX", 0, 1); + ObjectAnimator scaleY = ObjectAnimator.ofFloat(this, "scaleY", 0, 1); + AnimatorSet animSetXY = new AnimatorSet(); + animSetXY.playTogether(scaleX, scaleY); + animSetXY.setInterpolator(overshootInterpolator); + animSetXY.setDuration(200); + animSetXY.start(); + mHidden = false; + } + } + + public boolean isHidden() { + return mHidden; + } + + static public class Builder { + private FrameLayout.LayoutParams params; + private final Activity activity; + int gravity = Gravity.BOTTOM | Gravity.RIGHT; // default bottom right + Drawable drawable; + int color = Color.WHITE; + int size = 0; + float scale = 0; + int paddingLeft = 0, + paddingTop = 0, + paddingBottom = 0, + paddingRight = 0; + + public Builder(Activity context) { + scale = context.getResources().getDisplayMetrics().density; + size = convertToPixels(72, scale); // default size is 72dp by 72dp + params = new FrameLayout.LayoutParams(size, size); + params.gravity = gravity; + + this.activity = context; + } + + /** + * Sets the gravity for the FAB + */ + public Builder withGravity(int gravity) { + this.gravity = gravity; + return this; + } + + /** + * Sets the margins for the FAB in dp + */ + public Builder withPaddings(int left, int top, int right, int bottom) { + paddingLeft = convertToPixels(left, scale); + paddingTop = convertToPixels(top, scale); + paddingRight = convertToPixels(right, scale); + paddingBottom = convertToPixels(bottom, scale); + return this; + } + + /** + * Sets the FAB drawable + */ + public Builder withDrawable(final Drawable drawable) { + this.drawable = drawable; + return this; + } + + /** + * Sets the FAB color + */ + public Builder withButtonColor(final int color) { + this.color = color; + return this; + } + + /** + * Sets the FAB size in dp + */ + public Builder withButtonSize(int size) { + size = convertToPixels(size, scale); + params = new FrameLayout.LayoutParams(size, size); + return this; + } + + public FloatingActionButton create() { + final FloatingActionButton button = new FloatingActionButton(activity); + button.setFloatingActionButtonColor(this.color); + button.setFloatingActionButtonDrawable(this.drawable); + button.setPadding(paddingLeft, paddingTop, paddingBottom, paddingRight); + params.gravity = this.gravity; + ViewGroup root = (ViewGroup) activity.findViewById(android.R.id.content); + root.addView(button, params); + return button; + } + + // The calculation (value * scale + 0.5f) is a widely used to convert to dps to pixel units + // based on density scale + // see developer.android.com (Supporting Multiple Screen Sizes) + private int convertToPixels(int dp, float scale){ + return (int) (dp * scale + 0.5f) ; + } + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java b/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java new file mode 100644 index 000000000..a37532249 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/common/ProgressDrawable.java @@ -0,0 +1,58 @@ +package us.shandian.giga.ui.common; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; + +public class ProgressDrawable extends Drawable +{ + private float mProgress = 0.0f; + private int mBackgroundColor, mForegroundColor; + + public ProgressDrawable(Context context, int background, int foreground) { + this(context.getResources().getColor(background), context.getResources().getColor(foreground)); + } + + public ProgressDrawable(int background, int foreground) { + mBackgroundColor = background; + mForegroundColor = foreground; + } + + public void setProgress(float progress) { + mProgress = progress; + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + int width = canvas.getWidth(); + int height = canvas.getHeight(); + + Paint paint = new Paint(); + + paint.setColor(mBackgroundColor); + canvas.drawRect(0, 0, width, height, paint); + + paint.setColor(mForegroundColor); + canvas.drawRect(0, 0, (int) (mProgress * width), height, paint); + } + + @Override + public void setAlpha(int alpha) { + // Unsupported + } + + @Override + public void setColorFilter(ColorFilter filter) { + // Unsupported + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + +} diff --git a/app/src/main/java/us/shandian/giga/ui/common/ToolbarActivity.java b/app/src/main/java/us/shandian/giga/ui/common/ToolbarActivity.java new file mode 100644 index 000000000..7200bb522 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/common/ToolbarActivity.java @@ -0,0 +1,26 @@ +package us.shandian.giga.ui.common; + +import android.os.Bundle; + +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; + +import org.schabi.newpipe.R; +import us.shandian.giga.util.Utility; + +public abstract class ToolbarActivity extends ActionBarActivity +{ + protected Toolbar mToolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutResource()); + + mToolbar = Utility.findViewById(this, R.id.toolbar); + + setSupportActionBar(mToolbar); + } + + protected abstract int getLayoutResource(); +} diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/AllMissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/AllMissionsFragment.java new file mode 100644 index 000000000..452024223 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/fragment/AllMissionsFragment.java @@ -0,0 +1,13 @@ +package us.shandian.giga.ui.fragment; + +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.service.DownloadManagerService; + +public class AllMissionsFragment extends MissionsFragment +{ + + @Override + protected DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder) { + return binder.getDownloadManager(); + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/DownloadedMissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/DownloadedMissionsFragment.java new file mode 100644 index 000000000..1c8c56a36 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/fragment/DownloadedMissionsFragment.java @@ -0,0 +1,13 @@ +package us.shandian.giga.ui.fragment; + +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.get.FilteredDownloadManagerWrapper; +import us.shandian.giga.service.DownloadManagerService; + +public class DownloadedMissionsFragment extends MissionsFragment +{ + @Override + protected DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder) { + return new FilteredDownloadManagerWrapper(binder.getDownloadManager(), true); + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/DownloadingMissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/DownloadingMissionsFragment.java new file mode 100644 index 000000000..79d50904e --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/fragment/DownloadingMissionsFragment.java @@ -0,0 +1,13 @@ +package us.shandian.giga.ui.fragment; + +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.get.FilteredDownloadManagerWrapper; +import us.shandian.giga.service.DownloadManagerService; + +public class DownloadingMissionsFragment extends MissionsFragment +{ + @Override + protected DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder) { + return new FilteredDownloadManagerWrapper(binder.getDownloadManager(), false); + } +} diff --git a/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java new file mode 100644 index 000000000..51927051b --- /dev/null +++ b/app/src/main/java/us/shandian/giga/ui/fragment/MissionsFragment.java @@ -0,0 +1,134 @@ +package us.shandian.giga.ui.fragment; + +import android.app.Activity; +import android.app.Fragment; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.IBinder; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; + +import org.schabi.newpipe.R; +import us.shandian.giga.get.DownloadManager; +import us.shandian.giga.service.DownloadManagerService; +import us.shandian.giga.ui.adapter.MissionAdapter; +import us.shandian.giga.util.Utility; + +public abstract class MissionsFragment extends Fragment +{ + private DownloadManager mManager; + private DownloadManagerService.DMBinder mBinder; + + private SharedPreferences mPrefs; + private boolean mLinear = false; + private MenuItem mSwitch; + + private RecyclerView mList; + private MissionAdapter mAdapter; + private GridLayoutManager mGridManager; + private LinearLayoutManager mLinearManager; + private Activity mActivity; + + private ServiceConnection mConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName name, IBinder binder) { + mBinder = (DownloadManagerService.DMBinder) binder; + mManager = setupDownloadManager(mBinder); + updateList(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // What to do? + } + + + }; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.missions, container, false); + + mPrefs = getActivity().getSharedPreferences("mode", Context.MODE_WORLD_READABLE); + mLinear = mPrefs.getBoolean("linear", false); + + // Bind the service + Intent i = new Intent(); + i.setClass(getActivity(), DownloadManagerService.class); + getActivity().bindService(i, mConnection, Context.BIND_AUTO_CREATE); + + // Views + mList = Utility.findViewById(v, R.id.mission_recycler); + + // Init + mGridManager = new GridLayoutManager(getActivity(), 2); + mLinearManager = new LinearLayoutManager(getActivity()); + mList.setLayoutManager(mGridManager); + + setHasOptionsMenu(true); + + return v; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mActivity = activity; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.frag_mission, menu); + mSwitch = menu.findItem(R.id.switch_mode); + mSwitch.setIcon(mLinear ? R.drawable.grid : R.drawable.list); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.switch_mode: + mLinear = !mLinear; + updateList(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + public void notifyChange() { + mAdapter.notifyDataSetChanged(); + } + + private void updateList() { + mAdapter = new MissionAdapter(mActivity, mBinder, mManager, mLinear); + + if (mLinear) { + mList.setLayoutManager(mLinearManager); + } else { + mList.setLayoutManager(mGridManager); + } + + mList.setAdapter(mAdapter); + + if (mSwitch != null) { + mSwitch.setIcon(mLinear ? R.drawable.grid : R.drawable.list); + } + + mPrefs.edit().putBoolean("linear", mLinear).commit(); + } + + protected abstract DownloadManager setupDownloadManager(DownloadManagerService.DMBinder binder); +} diff --git a/app/src/main/java/us/shandian/giga/util/CrashHandler.java b/app/src/main/java/us/shandian/giga/util/CrashHandler.java new file mode 100644 index 000000000..5404e0d39 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/util/CrashHandler.java @@ -0,0 +1,84 @@ +package us.shandian.giga.util; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.os.Build; +import android.os.Environment; + +import java.io.File; +import java.io.PrintWriter; + +public class CrashHandler implements Thread.UncaughtExceptionHandler +{ + public static String CRASH_DIR = Environment.getExternalStorageDirectory().getPath() + "/GigaCrash/"; + public static String CRASH_LOG = CRASH_DIR + "last_crash.log"; + public static String CRASH_TAG = CRASH_DIR + ".crashed"; + + private static String ANDROID = Build.VERSION.RELEASE; + private static String MODEL = Build.MODEL; + private static String MANUFACTURER = Build.MANUFACTURER; + + public static String VERSION = "Unknown"; + + private Thread.UncaughtExceptionHandler mPrevious; + + public static void init(Context context) { + try { + PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + VERSION = info.versionName + info.versionCode; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void register() { + new CrashHandler(); + } + + private CrashHandler() { + mPrevious = Thread.currentThread().getUncaughtExceptionHandler(); + Thread.currentThread().setUncaughtExceptionHandler(this); + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + File f = new File(CRASH_LOG); + if (f.exists()) { + f.delete(); + } else { + try { + new File(CRASH_DIR).mkdirs(); + f.createNewFile(); + } catch (Exception e) { + return; + } + } + + PrintWriter p; + try { + p = new PrintWriter(f); + } catch (Exception e) { + return; + } + + p.write("Android Version: " + ANDROID + "\n"); + p.write("Device Model: " + MODEL + "\n"); + p.write("Device Manufacturer: " + MANUFACTURER + "\n"); + p.write("App Version: " + VERSION + "\n"); + p.write("*********************\n"); + throwable.printStackTrace(p); + + p.close(); + + try { + new File(CRASH_TAG).createNewFile(); + } catch (Exception e) { + return; + } + + if (mPrevious != null) { + mPrevious.uncaughtException(thread, throwable); + } + } +} + diff --git a/app/src/main/java/us/shandian/giga/util/Settings.java b/app/src/main/java/us/shandian/giga/util/Settings.java new file mode 100644 index 000000000..82ceb2826 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/util/Settings.java @@ -0,0 +1,60 @@ +package us.shandian.giga.util; + +import android.content.Context; +import android.content.SharedPreferences; + +/* + Settings Provider +*/ +public class Settings +{ + public static final String XML_NAME = "settings"; + + public static final String DOWNLOAD_DIRECTORY = "download_directory"; + + public static final String DEFAULT_PATH = "/storage/sdcard0/GigaGet"; + + private static Settings sInstance; + + private SharedPreferences mPrefs; + + public static Settings getInstance(Context context) { + if (sInstance == null) { + sInstance = new Settings(context); + } + + return sInstance; + } + + private Settings(Context context) { + mPrefs = context.getSharedPreferences(XML_NAME, Context.MODE_PRIVATE); + } + + public Settings putBoolean(String key, boolean value) { + mPrefs.edit().putBoolean(key, value).commit(); + return this; + } + + public boolean getBoolean(String key, boolean def) { + return mPrefs.getBoolean(key, def); + } + + public Settings putInt(String key, int value) { + mPrefs.edit().putInt(key, value).commit(); + return this; + } + + public int getInt(String key, int defValue) { + return mPrefs.getInt(key, defValue); + } + + public Settings putString(String key, String value) { + mPrefs.edit().putString(key, value).commit(); + return this; + } + + public String getString(String key, String defValue) { + return mPrefs.getString(key, defValue); + } + +} diff --git a/app/src/main/java/us/shandian/giga/util/Utility.java b/app/src/main/java/us/shandian/giga/util/Utility.java new file mode 100644 index 000000000..acad26209 --- /dev/null +++ b/app/src/main/java/us/shandian/giga/util/Utility.java @@ -0,0 +1,334 @@ +package us.shandian.giga.util; + +import android.app.Activity; +import android.content.ClipboardManager; +import android.content.ClipData; +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.widget.Toast; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.schabi.newpipe.R; +import us.shandian.giga.get.DownloadMission; +import us.shandian.giga.util.Settings; + +import com.nononsenseapps.filepicker.FilePickerActivity; +import com.nononsenseapps.filepicker.AbstractFilePickerFragment; + +public class Utility +{ + + public static enum FileType { + APP, + VIDEO, + EXCEL, + WORD, + POWERPOINT, + MUSIC, + ARCHIVE, + UNKNOWN + } + + public static String formatBytes(long bytes) { + if (bytes < 1024) { + return String.format("%d B", bytes); + } else if (bytes < 1024 * 1024) { + return String.format("%.2f kB", (float) bytes / 1024); + } else if (bytes < 1024 * 1024 * 1024) { + return String.format("%.2f MB", (float) bytes / 1024 / 1024); + } else { + return String.format("%.2f GB", (float) bytes / 1024 / 1024 / 1024); + } + } + + public static String formatSpeed(float speed) { + if (speed < 1024) { + return String.format("%.2f B/s", speed); + } else if (speed < 1024 * 1024) { + return String.format("%.2f kB/s", speed / 1024); + } else if (speed < 1024 * 1024 * 1024) { + return String.format("%.2f MB/s", speed / 1024 / 1024); + } else { + return String.format("%.2f GB/s", speed / 1024 / 1024 / 1024); + } + } + + public static void writeToFile(String fileName, String content) { + try { + writeToFile(fileName, content.getBytes("UTF-8")); + } catch (Exception e) { + + } + } + + public static void writeToFile(String fileName, byte[] content) { + File f = new File(fileName); + + if (!f.exists()) { + try { + f.createNewFile(); + } catch (Exception e) { + + } + } + + try { + FileOutputStream opt = new FileOutputStream(f, false); + opt.write(content, 0, content.length); + opt.close(); + } catch (Exception e) { + + } + } + + public static String readFromFile(String file) { + try { + File f = new File(file); + + if (!f.exists() || !f.canRead()) { + return null; + } + + BufferedInputStream ipt = new BufferedInputStream(new FileInputStream(f)); + + byte[] buf = new byte[512]; + StringBuilder sb = new StringBuilder(); + + while (ipt.available() > 0) { + int len = ipt.read(buf, 0, 512); + sb.append(new String(buf, 0, len, "UTF-8")); + } + + ipt.close(); + return sb.toString(); + } catch (Exception e) { + return null; + } + } + + public static T findViewById(View v, int id) { + return (T) v.findViewById(id); + } + + public static T findViewById(Activity activity, int id) { + return (T) activity.findViewById(id); + } + + public static String getFileExt(String url) { + if (url.indexOf("?")>-1) { + url = url.substring(0,url.indexOf("?")); + } + if (url.lastIndexOf(".") == -1) { + return null; + } else { + String ext = url.substring(url.lastIndexOf(".") ); + if (ext.indexOf("%")>-1) { + ext = ext.substring(0,ext.indexOf("%")); + } + if (ext.indexOf("/")>-1) { + ext = ext.substring(0,ext.indexOf("/")); + } + return ext.toLowerCase(); + + } + } + + public static String getErrorString(Context context, int code) { + switch (code) { + case DownloadMission.ERROR_SERVER_UNSUPPORTED: + return context.getString(R.string.msg_server_unsupported); + default: + return ""; + } + } + + public static FileType getFileType(String file) { + if (file.endsWith(".apk")) { + return FileType.APP; + } else if (file.endsWith(".mp3") || file.endsWith(".wav") || file.endsWith(".flac")) { + return FileType.MUSIC; + } else if (file.endsWith(".mp4") || file.endsWith(".mpeg") || file.endsWith(".rm") || file.endsWith(".rmvb") + || file.endsWith(".flv") || file.endsWith(".webp")) { + return FileType.VIDEO; + } else if (file.endsWith(".doc") || file.endsWith(".docx")) { + return FileType.WORD; + } else if (file.endsWith(".xls") || file.endsWith(".xlsx")) { + return FileType.EXCEL; + } else if (file.endsWith(".ppt") || file.endsWith(".pptx")) { + return FileType.POWERPOINT; + } else if (file.endsWith(".zip") || file.endsWith(".rar") || file.endsWith(".7z") || file.endsWith(".gz") + || file.endsWith("tar") || file.endsWith(".bz")) { + return FileType.ARCHIVE; + } else { + return FileType.UNKNOWN; + } + } + + public static int getBackgroundForFileType(FileType type) { + switch (type) { + case APP: + return R.color.orange; + case MUSIC: + return R.color.cyan; + case ARCHIVE: + return R.color.blue; + case VIDEO: + return R.color.green; + case WORD: + case EXCEL: + case POWERPOINT: + return R.color.brown; + case UNKNOWN: + default: + return R.color.bluegray; + } + } + + public static int getForegroundForFileType(FileType type) { + switch (type) { + case APP: + return R.color.orange_dark; + case MUSIC: + return R.color.cyan_dark; + case ARCHIVE: + return R.color.blue_dark; + case VIDEO: + return R.color.green_dark; + case WORD: + case EXCEL: + case POWERPOINT: + return R.color.brown_dark; + case UNKNOWN: + default: + return R.color.bluegray_dark; + } + } + + public static int getThemeForFileType(FileType type) { + /*switch (type) { + case APP: + return R.style.Theme_App_Orange; + case MUSIC: + return R.style.Theme_App_Cyan; + case ARCHIVE: + return R.style.Theme_App_Blue; + case VIDEO: + return R.style.Theme_App_Green; + case WORD: + case EXCEL: + case POWERPOINT: + return R.style.Theme_App_Brown; + case UNKNOWN: + default: + return R.style.Theme_App_BlueGray; + }*/ + return 0; + } + + public static int getIconForFileType(FileType type) { + switch (type) { + case APP: + return R.drawable.apps; + case MUSIC: + return R.drawable.music; + case ARCHIVE: + return R.drawable.archive; + case VIDEO: + return R.drawable.video; + case WORD: + return R.drawable.word; + case EXCEL: + return R.drawable.excel; + case POWERPOINT: + return R.drawable.powerpoint; + case UNKNOWN: + default: + return R.drawable.unknown; + } + } + + public static boolean isDirectoryAvailble(String path) { + File dir = new File(path); + return dir.exists() && dir.isDirectory(); + } + + public static boolean isDownloadDirectoryAvailble(Context context) { + return isDirectoryAvailble(Settings.getInstance(context).getString(Settings.DOWNLOAD_DIRECTORY, Settings.DEFAULT_PATH)); + } + + public static void changeDownloadDirectory(Context context, String path) { + Settings.getInstance(context).putString(Settings.DOWNLOAD_DIRECTORY, path); + } + + public static void showDirectoryChooser(Activity activity) { + Intent i = new Intent(activity, FilePickerActivity.class); + i.setAction(Intent.ACTION_GET_CONTENT); + i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); + i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true); + i.putExtra(FilePickerActivity.EXTRA_MODE, AbstractFilePickerFragment.MODE_DIR); + activity.startActivityForResult(i, 233); + } + + public static void checkAndReshow(Activity activity){ + if (!isDownloadDirectoryAvailble(activity)){ + Toast.makeText(activity.getApplicationContext(), + R.string.no_available_dir, Toast.LENGTH_LONG).show(); + showDirectoryChooser(activity); + } + } + + public static void copyToClipboard(Context context, String str) { + ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", str)); + Toast.makeText(context, R.string.msg_copied, Toast.LENGTH_SHORT).show(); + } + + public static String checksum(String path, String algorithm) { + MessageDigest md = null; + + try { + md = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + FileInputStream i = null; + + try { + i = new FileInputStream(path); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + + byte[] buf = new byte[1024]; + int len = 0; + + try { + while ((len = i.read(buf)) != -1) { + md.update(buf, 0, len); + } + } catch (IOException e) { + + } + + byte[] digest = md.digest(); + + // HEX + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); + } + + return sb.toString(); + + } +} diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..236bff558af07faa3921ba35e2515edf62d04bb9 GIT binary patch literal 161 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..481643ecd5e5c361bdf5440f80b6ead58c015a87 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?|m)`b<0N2FLh>sBaz zbNHm-*5u;7=mneO8+En?J13^G1)j}b{4(Q;!Yv7xt%vHjER#LP#>jBmH-z#3;kA!} PRxo(F`njxgN@xNAMifE{ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_menu_more.png b/app/src/main/res/drawable-hdpi/ic_menu_more.png new file mode 100644 index 0000000000000000000000000000000000000000..928fcab8f88840aed523308b31ea96779d59d074 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-segQrqu0Z-f^}vMb(z-wsrAmVQ zf*Ise^{@Wf^Z&>5R^FD!EZm0D8|VG|vdM_Ad4`0=0-&lkPZ!4!kK=Erc=I(V@UVui zS_+O*2cC_iiBErx{~#d!thaPe`h<Iyou4i_zNm_H?KqUpk|dC@gdS3Z1x>&|hU sk7d2(4{Lvs=?v>6V^Vf#)!#eL$!WtXzPrrp4bVjlp00i_>zopr0J?aixc~qF literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/list.png b/app/src/main/res/drawable-hdpi/list.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3f54c20a192167c1908651dd9357e0266885ef GIT binary patch literal 3129 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/archive.png b/app/src/main/res/drawable-ldrtl-xhdpi/archive.png new file mode 100644 index 0000000000000000000000000000000000000000..70ba10c53709457cf73752525c0e8854bcdb87e0 GIT binary patch literal 26362 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 B8+8Bx literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-ldrtl-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fabe9d96563785c7d6b008bb3d8da25e816c343c GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^{6Or)!3HEd1bTh|DVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?08bak5Rc<;uP@|nU=UzFz%6x@#ly{E6Z5RU$2Hhw*i>Gs`(~~C zr~2_>(e4Ka`gpa)&de}Ks*u{@U5E@m-v9X3<$3NT3r3p*`<7|@n1Ecw;OXk;vd$@? F2>^8yH@N@+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/excel.png b/app/src/main/res/drawable-ldrtl-xhdpi/excel.png new file mode 100644 index 0000000000000000000000000000000000000000..fe19a65000f310fa2d378ee7c6d94dbc89caecd8 GIT binary patch literal 30001 zcmeIb2{_c<`#=7k8Dn26YnF&X$uh&(*OHj5$(B+WYsQj&iOBF4;DY80|5}k#!deVgVHhtAc)n}Q(xc0 z!oxSvH^9T!PYkE8FXrd(>*h&tg`m*)nfpWRlBW4|dZt~uY<9h)-A^TuAaRKT=9e1| zT-!i~oPOJ|Nw50kX;vE^-i;YX)-O)9u^MHb{+zw7)P3jK)Ar}A52<|@?aqC8JbZLy zWWHm*d>~_Bp((7Hi@0%;gS; zc?QZ|81cX(MMF5T0tp4j+a+-6IYPwCyJTNMVrp zC=C}IQ;l1dcuFs}2!@Q&sGqlfenz;z%ZY#c1~-;I@r=}T32vhSgh>-S1PRW*e!8Tl zn=tUD@6#8z0mA4+^|d80ny%oH&<3;S(f3FC``ZzIwXnjVDzChQ(0d!m zqi5DZsf#7sp0y=>_FS0Sg5H*_s}?V{M1)z{*hVCsuU4RY&*>~Hee$KAi<$y&m%74f z(6KbV%XcW(V-}A&`2^p!j2~!V*oE<#9*|h7JsG_izy0-R?EOQsyk~#dohh{tH?0kO zY?-)wYu&}qn+Bs5e~6|mvLuCYKn17FDQ1tD9ySmtQQu+kbDVaq!H{0mxZHU`wnS)y zJ617l8iJClW-sXNfI*F^IlT~6{#D@6tz>?a8fFOEolTM{+{wiLl&65gnekMloWc)x zV%)9Aj-qI7*u~gK6lT3Dkg{{L6-DD6!^1*^VD`qePaBG#V$?VWsGAOvhWz*$9R;$U z36!5=Vc7YSncHcr#_5gD@$bZ&nE5ZqGl)AGVadcCvBA?k`^2kX`scv&b{$Q0Fp?OP z^XE~IJES+4(DhPG@$ACcazjiq>A^n4TX>M(<6EMFXKS(pUI${i9Ed5`yj}|yZ_y?` zx|aLe_-jxgbo^{Qp72|);>CpLD1IIIVf>O17_^GsSi>6Ur1Wca4p7opA?_Y>^) z6i9vFx@BvYnfBtuYg+i>#uRw zrAwv0$GZ0_hw|&V75EA}7hpfSc6(_#IeRL0<-EwL?yKD1nCzA2R`$C1P2j6nFJ-$6 z-WAjh$E&wxcx5?Nc9wT7#GSlhkWsz&oXWY{l=mr-4agMJl<9&?Haa$8Hj_3T1-SM@ zL$X8O?Y0C9A=`BJbdB_eN4M^z-+2+7?%l)lndidx*6ow~ecoe+7lv7f(}o#G)Tf-L zB&WQmnnhj-ZxU(O4AhMD4-9%0OzQ z`S*M0p3U{S65epJU+{Zb>%%vb*VCV*ci-vse*58-cJ=Yw^QQ9YLUj($wMTbO(5CG^ zAA8lCnVX*bY&>B=;c)Qb1Bd4;wwM=XNM*I7yN&f+R>PLUZU+$6wAn&z8CLaXrJi~fDaJTlrs9# ztWpB;cl*1qJ?8&1*wl~}qIE#|KtiP2$xEA3AL#bSi0!ga5HRo0^)VIU9{Vl*q`5)m zwYY2h?w6GA)gph%w7EE?_CfQw{+!1t^F2W|N-XAXG-yo4s^-35_7j5JCZp1!oGOd3nj(YPxnd828?&{5>A@DzFus3*MgJJ zMB&zs(1QX8LraY+jO^bk^|&p4o0VWY!53MPP-szFSoE$m^uQ0Qc$L8uK8bVt`9tI} z4whvup`NtX;|(4S4^kE_KHFJZj~xx`9*eh(X}xhnf5!=1?8Us~x(1)S6ZVhsyiONg ztVfTgwjH#Imf^p6q`*4>%HJ*8hh+nOC|i<}Jee*gaC-je!}A)}$3A)kWj16B9- zRvg{g)^du*aYyJ!T))r}@4X)buZAC;jBhM%tZzgpJ1LJGeD$cHYwW7Z^{Md8Xom)y z#XGl4Dm$g#w^w}#i5TaM5#iPRIGQ|M{%}XAtyhJ?@kyW7?^s|@Ye73XysdUfH z$cSExuUDI%cRz3Jxg1?G$vk8fwxd;}DyTs2x_7qr)r!%t=dWjq92POGELn~k#q{EX zYLze8W@Tq?)BZ8rcOt1b*CjVA(@ay%R_-?;KJDBkSz>%g`>wWOl;7efqk9K^hg_!{Mr^h222Pj`X}%tP6Fqm7(iYG$ z(;@G0C9Gn!W>~1iN9u!csbtyYOz_kQe+cV$lWvFb3!(QGD&H@DW18do7G1n_-<9G` zopGc%Ha|bWHOk2no3)g@{3iBOtKlodHi-o&`Vo4J5viW zeP4f9F=csWIXoJJ6;oB0$0%d4Y8Y8DMKnf90j;EfQIf+bYM|9MFv?=T{}I<=1uZRq z7dH*d-FtrT4*W}7+#@j1PeVZ=BqT&WL`mM)-(3NtuCA_tR#Z?_lmilS0bxFYPN8x> z0TMrr{9$LeYXIKg(=X7|*GG(Q*U8y8C{SBmoZivupWo-@?YG*IPr&ck0TdNNo%|Fq z@@R#>Q*yzt>i7lu6IO=if>&@QxO%(#1O@;-%-`w(NKH*wRsXg-Z|}d=3|gEpx_G*Ut;x!tlE2t+!E3nr`g=PC>UerPxw|U(`M7H- z{Q2+~$rZ=d!1)9OI{DyTal3WE19?wR7Y#QzMOTcQikh6OlaiC13mWSz=Y(-nms3}A zQpP%?UDREj-B#c*HT_lnpG@!e#Rt)2=XcXCz_g31qMEuQ#zjsIi^0fYRIqAtYA#L~ zIX7h`WhW;$bww=3#Pugh7+F7Z8~_mSGxif{^9AL z!&=q+UCr~K7jSJT|Fr*$`oHcY#KYC+zY2|?rdFi>wUGc{x4;l5f7hMvz$g9>0sGV7 zKWhBdvX%mU8z6Z8|F8xDPQm}#3SgAg(dtTyE^>-!H#a#I4Aw=?+06wjhj(>W#k;vU zxj3WM{#fCEcLfxcHPDKG(8~Xl75LM4@g7b-?yfF63V%%Mj|cyo77gpFq^72hRhC2J zl`(Q?CoD!z9iyZq=i;KGqN=QlQFm5f4af-9}`QPD{ zUq*@l117QmWpnQU3?-{N1|Cznk>`9NaJJe`nqIKh67p_VPDo z{_O1!L_U`{N3YUZ2tKgTo79PydTsFur%ByhBMGt z!KkaK$SKNWel_!p+%I-3e^ov3U#tH5`md^gYFhhv2I?sO-rHXu|Dr`d>Hh?EKd5fG(x>*-^B>zlvTJn%0ye|ht}=FcGgr3$s;6hEJW8W$+9DXiAle({&p zt6^gYq*5O(UN~<#KaIHeImc}|r8tZVa z1*KJ)b+}fcSW9CauC<`FDzgsPDimvJti!bylvZWd;aY`aEsb@!)`HTi%sO1FP^_h~ z4%b>xT9sLcYZZ#MG}hr-3redp>u{|?v6jX*Yv?{X>*D4fiX{^Jw7L-V`5 zN>NHUwRMLJnR!oawsBmxq=gat)C5AMZtqdSuC^ILE!GrQuNK+YUoE?c&gVCd*xym{ zOqZ(9-R)4x&0(a)dVW*Oi5!?eYamYP?N;{7Xx>W@HY{>4`J0Ds;l`QGwEffr)E-&r)XnY2Gtum?7BQwOd~# z3w0|9)&fOtXPeP)szBiu6zBC8n)MpV{&H-@Gn5KS;D9|jXF8Ozl;@qrxg+g%F+H!@ zBSk_x`xJ1k8%>-2`=7~%@RcEG7^*0#D8m*m=zSs6DmAYI4*&+Y$L$j_K`%Gb{ylP)KOTIs!%v%(j8C0 zSX!SU@AfL-EJp|ucZ6u++N?w_c=IQ6B^lNBT!9oI(5DTHsbD~p1D{{1J3`Kxo3Tha zXV{((dBC?kd$K5r%P+wlF!RYbfca^n-(XTv+xgw#(Mm0%f?u_vBhb>x;yd?HxcUnU zaNS#bV6=@?Nour44H?znI*ZqWZ5$s7f^qE`Ec`xk3>FL#03>w2Q=rsM5A!q8dv@wb)B7Pz$tYa)q$YKm zn8~zhN%Yc!B#!kSreW4s`gqqe8Flgbs~9%o=J;3??gm<HuU!MzKLSvI|TM zN0x<9I5Lum!aaZzP&ht_{NE7zA2G5zod0Abt43Dm^v~1Dx#ktj9LTOol6#6LFx6|5RU=P5oLh!XL7FeQ3>4HI35KjT7Lg1QwH=Ivmz6Si9Vjn`y{rZpb!}al z^pu0S(Bh%arB6LMefQD&bm231-^j8-)|O0u`)LAI#tZF!mxEkS5?oZ>2J!<<4#QjY zhM8`{ZzF2e*h0JWI0u!U4otB-O1AV_HEs)qc4Utk{Mq_ zKv+9-gc9jit@)0@`;_3^vX)2g)kj0#R(+x*QP^|s!Nhhb5zoPEJ2)agc*>W1A*7=p z1hn)iXhQjqRZ06#Ke-u>plPA2^W<}^b8>C2EyW43mBTZr^r0U0<|)MbMINUtP*{GW z2B<2`bboLiOGOgD4F*s$C_nBnZ1GED8+c0iel0C2Gom#+j79HaVO%ku`aSzc93pCG z8OCC^gCm21z#-UUWH}U_v0o1KTM|rt1SW&@2~K0{O`+6@Qf-o|hM{fdbHqW)+3X(= z6Q*oKGAARuOup@zWQg+>q_Gb&TGw$B$M%_!Q&@ah1dniep498_Y9l2r(}snWW*gvo zkCiss38+=}=NQ-~o11Tp5RDyr5MYx3Dpy4TcI(*`EEh3!qNanToB^xZ_PCWTV^8-; zhBQoJQ-p+kC(Pn0hs49}*T3&=M|KZk2bvyG>Z-P%Yo?9 zjkuBS;f%!mdSfWx^;!nQFpI#!pT6-}>Jft5=*g0S(uv~JDG_EbIf>7{LO!g52UTf7 zxutG*InowjKG<2%oA`S!6QqryRw{9TwB0Pg`c8fP)zi@>O_0r|5MEQ@s(tN{J9&!z zwA)@AhSGxvgC=0^?l{FXrvpw}ot`##K%hNT*=)A~`{*JCVRo!dO8`5Yl*ug>4X_T? z?i76z2g3_7Eu09%XUpUYsj<8hL_gvtJ=8n*MphF#d-r7V^}{c0W^E2VsSxyGNm~#y z(p?YFGMOCc=@o1aJ*cHY@-zMrgi4#6T#QkTcOKp_~4-?IDOOKQp zbu2~1R4Zo`^Gxl|wF`!FLeiOK*#&GB(9MG*C9|+3T}lugvxInpsGo+X`Gm(7sSk^H zBo3N|%b?P5lyfOu5t&9C@jG_AL zMZ_KOnunY1K2L0UO(xcfI^LzzUe3~x)CX*dq}`!AIq4!@nV&;CIZa-E(I)@MNf-Pe zVhJQ*sQOVxIYQ<4iOSlCU`RRcOQuT?5Mmt9Qc0tRnxn)kiSj|)K8#~{PfwM6g;OKU z?#V(qPdh>M6Wj|+Z$i!P)q0mFVeW_>V6JJ!k`n^vPW=~Cq2v%eu^QHE&!R=07;~ib znFqg0qc3tkv6FKBsk0#PkFmoN-x7`A^X~8c3EbD4(k`)uu+Q& z%0)0-N4n4C&4oYEeIyi9J?Y(A_9OAQwBvbcxEG1f90Z3^+cY*WPIz#}n@$>hflVvk z;k0xLZVp${lC;KxLG5dV&DI%lp|5OMAjvuM=-4LWiB6^r&H^@` zH$2o?`0=q}M3dCWdH!k?)u8pJE?ETH9(yYBeR1L=7l#9d=5M$djh9R*ib+*qsTMTZ zO2OK*ZLgV}xYkqRrxt*75CBP$4AB?fi>NN*Eqx4)j;9P)?7>uu^~!TxnufMLFeHw{ ztKY!O_u8YjT~JBlTO4G;e$nL&X2$`dW-TJIfwzc5nZ45?L4|$Mq?Mrf{66ux%!kd} zZUUcBk1#jyr)hIkdsvpZp3hAHK3I(fIfU%Z+b=ts!hugbtqHxqGV345ku!ws&@y5~ zz(iDv>*)5g0Y&&dtc}Ky%(=##>O)fuXL93;&Gimu_SDL^ehYna;`|VEtGJ~|mLkBj zx&_wFvn|Vk!l522dJYa<F_rs*6M~u@-P{G6z1aO*8Cn*&8lfSW#c)u8Af&51YIb<#$ICU6}M_61%(-&|Wuex@d=m zw#{BZ`ix@}kVGq;>%<$R&tZ_Ab#+Jd)_IYA-N+28rx+WQm!ZS-ie;0rD9B?fWh$nu zt;0vcFC{frfSmB+J3zx?_X`SIb0?UJI^rEsG;gj55NSuH+aFR-T1{yjzw=$;*2ROQ zV_T-cq!|X!5IuJ~cd~XLdfM?sGNO_BCM-3))L4gcn+O5nC*yfF`y@RG<%Y<8kIxa6rYC^4v!w56!5f;&>+>}>4 zmxlN2&vcewW+*qxh|2~foX7f;gyqXtb`r$GXY!845C2Y4=}NwFi1RNXQz!%pq4kjcpSE$ zP7E(L$rP3QR6HbaVIwpzEeAWoFMilrc({_+B_0L%CjJmh#%8g2{gUYl6{9g-L}~qV zE1+imJgtEFo$W+`=*)qsAXbZsD#UYQ8^widADE;SM-mAM`}`I0#r4W1iAZKUz`|e* zZS6^t>2aI}@)^tpNPA&cx}>RG4o9${@Y%WO(_6g{xs0U(=198)JJg4M`@x{|kddIr z~Htwt97_HKm#?^U@fy3<^YKQutz>jcO1Mdbjnr0&hB-%{z1V zIof3!9AklJdblC@)!1W#VSZW9#jNRW`0f2pd#TV|eT>+3k}V0td6FKn*Dw_4SSJcd zD}lFLGJx}t$f+pxj{D${nX?TrXHjRbg>V}nti2+fC#@X76pmg;l-4<^-2_BMA8y(r z#me!a{xLguXvZ;L1ArK-2Zx`OXERiRx3dv24c?aXp0 zDS3Srq5|4!`D_6)!m_b<>w;J-D zP3uf8{2nA7x{a=;xEU!ccWfbK#d$3+XL89Z9C!s5FEgBOqR2Z(1QC*o`k0v0zO0se zIA2r&W;EHs*=>I<)E9so451{CQvw|gXll8zW~xL2m=bQ3r;n3FkM2X?5m|COGj@%+1n;>n@y_L=HkKvamSO-sO+w*YWW)}8rjcRJb&XMx3SSwZAw394CvW_ zCPusUyv6r|8(u2!EKsrTFr)T%+D`U(w8oS0KjUooxXDtCe8v||b^uh~=`FCP0D)6| z(iB4MPQW^6ucZfeEDLc~C!A+0Bih97%9jO@wH>Rds}g?%b*Qf>(eqYne(=Rs1}&zH zehVYu--kye?o3v-U%hpUp5AIBP}W3%UVYhzz9YOt#4ce*fOWDVNTf+yVz0^A6H`eb zo&cQn=X6?qf~A(f4c67X}Tg^3Qh^0+J-A&R>_--D*s5#;HRTetmOy2ogkoxc4xBTHS7i3yep#h{jph}&VG z-(6}vLtnnO0!i(GgRl;-y>O z4S$jmNuP#{7L|lTv3kNHfW){e@KFl1A7XXmMHGoG55Nj~-rB-WUV!lh%+&Uua$lA^ zVOXS|1b`JR&g_)#rEecBTF1cl5%_ca&=A3E{YKvv9bd7L7t%?Z^FNM&rHJl1rTv166@jFw`;v`TUyLeP7t!alaG*_2PY2wOE1M^+9k23~gwxg5uek zJ8;blo+UAIoF0XNcJoBz(?vPMBJAI9RxW+S+A+-I8W={$X(=EmB_3xMe==tXARf@4 znZ4ZUwY!kBwDI}RjX8t>nIXgBFBFCC%|Q%ysGmCvb2R(+fs5AU)!Mk+lGss7%_mm zWB|wDTr|TSN~7|OcF6{Jhehw-UyRB6MQ4Zd!F!L=BHkDE@K!HU-ehsgNL+ziY@URY zNO3zq4~l(g`)GN+r-Xk-%`-8ZSqkzxsuo3$Z!;hEWZ)egYGEABQSLlKMfhESwUCea z)MC_xp1)$qy7gvsDNrOjM}eWRCd-a8^O$Q6-mfYjeetsvhMls7hlKB?6It|a;*%5AR>|I>UJvDt z$$iKa*-xK*Eyx9u_yW#2v(mI$EE1->m@-W5ZB)@JH3Q_eK{MA0ji09CF;hh8WBVv1+lr zq9rG<9MXv^M_M7cG+>gZYmS)7#4;7_tQ4?8<&W-h#1~!?fAo?|`mT%(SwfnrASSMyF;Det@7bG449#VmcRtpH#teOC71g>!sxrT5AZf% z6dX@ETYdaBK`{jxx@G#}D58nchVh&i7Vrrs>lt03X@OW*1+#M=i;j@}&aB3#c_!>a z3?P)WP==Yqlv4Ru8qnUR`WjT)sC#W;a`U$?P$0_lX+3-F;EC$Cy=6b{eb^qAIzsu4 z@KIv3`Foc8ZQD}-n$dUJE&&QiTj25{sHnUqun5w<&6-Zhp||scpdsA3<*%Uj+_P z+hHZ@74_T-ux;ilQ0^vQ-$^&Bd?tlaW3e>mln|OW9|3AJ`+@1+~jqP;%Jk zD$8gOs&CqwOkj_`Sg%A`+=)*&x1X}T_kVGHIX)1lq39ME7D?qlbZxnG|=z@*m} zWTVo)aZyXtFz3D1TQHh90;3cx0$$U;;uD^C&x}wQTH{Es&x?7B4DUyQZqf2wplA$y z!s{qO<;%vAr*ZV$mZW9W{m7esY@E4p)Lp?(v2eRbB;em;X`o;&-j%p`_2Xu2Wh^Mr z=1-+0rLe?%tT?Y(QGPY3T0fcvm2}ypXop6ajtKTq<_m{K3s9?p|6WutZu9+FRHtty zHPgM60dRENcFV`P=T+e4I$eGZoa&`LLF$+*!3iP|QsqKv#N(30E%ROhX#r03OhfSX zMN+dQSU2=-qAydtZ(^Np2=YMR!->(RrtQFA{k`e6R!q`q4P3`kdgix7gOVTET6nRQ ztL$5UqYEw_ZFI*jDS8RZ9kKaCQ0HU1L3wX_4soJJHFl!AYHTR7bq?CdAw6!y04zPUy$Iur@Z*;XfPLX`!Fs;W2)n67O#gTf4#I&dH34B3_vIzHh zz4*wEv;Hgzal93znt&qUK5Y{a8pmX%<+z30(2mOJ&OCr$zLW0Y-EVCqdTsa*R-P|f0a(MqkW+FbhFlhcdkeu)2qx@XB=kSg;&++3;?dOj7FX%=Lc zN$G!zU)U3TcW-T$VCv9*^3%23^p-Wu4C9skHXE(wBIGlg;I{6=stX>EI z^PM!$Rp?zW+K6l=v;2X1LW2|BuGd%Y$?iIqfXcI)!ort7sja-cw{gb2b|*Q$WSbs-^&xiCMDylegk zDO#-*vin|YMCN(l^|E1;i_B#*08gQMwDoPXL8aEBmq<_vZHln{=eKi$=J~EZV z&Igr)EC2ElN-U{o%WVYhpyQcd@T~xIh;Z7%g|{%s1G&TzTGcCsvveAPbXXU@v@ExT z{wDgBajE7Q_;#hmNB7W}u00b3zO><|#0u-;$gBgY6ddJX?EHl|!`Y`LL}dIG@QFrX zV_bI8l}SHLn0+{^_e{hDhr)&ulV{1 zQ`mgr^8WOPH_pwcFEH6d&;n#PEMQDd-eF9P-u#k_y>Al*W=g?>&od5^bIKw%sqw!% zG6IJjQHAhJeWk`^E7c*QC*?b7iR#D(t$a&k`Ska1X^2NSzQhW}(#}OAU%?-#Gl9o% zAIUN;A1zd9QG20E)1Ym3d=jt~XK6}k_8%S64@<0JEl;$?MIZ^s%uu-ee7OTn$AfMu zytTWkI-xNr^;=L=9Qc;!81+c`f0cHg72{ct+Wp`X+24+tKt(O#+afUHq9iD@4&T2 z6o@@sP<{J3RknO-$fxR{9=OW}1)^DDo)kxECJsFKZ8?17$IwJpqW&Tm)g_yI z2HgTXkJy9orZ8upoOnS(;SiI2o=#cX6!}(%`GcfJijW?^=fRK5^3HzC(NOI88S4Xm SBfvi)2xnln`|d8s6aOD|gUL<+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/grid.png b/app/src/main/res/drawable-ldrtl-xhdpi/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..94bb67f931c3175d5a779f77bd7900217ea1e084 GIT binary patch literal 2960 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/ic_menu_more.png b/app/src/main/res/drawable-ldrtl-xhdpi/ic_menu_more.png new file mode 100644 index 0000000000000000000000000000000000000000..13596f594ca0e16217b2a4a4fb6a91025d733d72 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!>H>U1T!HlefdlW?wM_!LK&vFk zFPMSDVCO^q?vH==eE#5Y(} zQuhL{@Bx#OEeAHu<-YC29rJ*x;3CucpN|%@)*X1wEU(LbRMZquVxaVXEdydFB zkxDnorJGir+FrkWS7w$|qd7xrFPcw7DV+j*B*jVn{j?s$K7;67KqcK&%*Zp&LI9(whae`<8JD`a6h$p4e! Yh$x?GZPv~eKo2o^y85}Sb4q9e0Q_YDcK`qY literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/list.png b/app/src/main/res/drawable-ldrtl-xhdpi/list.png new file mode 100644 index 0000000000000000000000000000000000000000..905e17c8ab494dd657c5e2573c8a47ceffa27e3d GIT binary patch literal 3006 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 A-T(jq literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/music.png b/app/src/main/res/drawable-ldrtl-xhdpi/music.png new file mode 100644 index 0000000000000000000000000000000000000000..130f5da300454af0f459ceaff21d10df5b209d3a GIT binary patch literal 28646 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 E0{-^`SO5S3 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/powerpoint.png b/app/src/main/res/drawable-ldrtl-xhdpi/powerpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..7d6ca29bc28befc4f75e41be63c48a4562b378af GIT binary patch literal 25507 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 I-S)@+4{>-KK>z>% literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/unknown.png b/app/src/main/res/drawable-ldrtl-xhdpi/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..5e535f265e6ee6a4b4da5fc0f01135b3c52969f3 GIT binary patch literal 23363 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-ldrtl-xhdpi/word.png b/app/src/main/res/drawable-ldrtl-xhdpi/word.png new file mode 100644 index 0000000000000000000000000000000000000000..34f3685d813fa98fe85a7e42e0f4d0432ded1f86 GIT binary patch literal 29211 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 D%QBq; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/grid.png b/app/src/main/res/drawable-xxhdpi/grid.png new file mode 100644 index 0000000000000000000000000000000000000000..db749798127e1dd5b9a40603fbe7cca317a8b46e GIT binary patch literal 18221 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 Z62MTuf)7V!Tj8+Y%w)ZBnxV^{e*qu(_>2Gm literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..72cedcad4f1bcedad5e0b69728dd893c52edf322 GIT binary patch literal 222 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/action_shadow.xml b/app/src/main/res/drawable/action_shadow.xml new file mode 100644 index 000000000..e76c1566f --- /dev/null +++ b/app/src/main/res/drawable/action_shadow.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_downloader.xml b/app/src/main/res/layout/activity_downloader.xml new file mode 100644 index 000000000..db8aea4d9 --- /dev/null +++ b/app/src/main/res/layout/activity_downloader.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/layout/dialog_url.xml b/app/src/main/res/layout/dialog_url.xml new file mode 100644 index 000000000..b797325c1 --- /dev/null +++ b/app/src/main/res/layout/dialog_url.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + +