package edu_cn.pku.course.activities; import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v4.content.FileProvider; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.MenuItem; import android.view.View; import android.webkit.MimeTypeMap; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.r0adkll.slidr.Slidr; import org.w3c.dom.CharacterData; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import edu_cn.pku.course.Utils; import edu_cn.pku.course.adapter.ContentViewAdapter; import pub.devrel.easypermissions.EasyPermissions; public class ContentViewActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener, EasyPermissions.PermissionCallbacks { private static final int WRITE_REQUEST_CODE = 300; private AttachedFilesListLoadingTask mLoadingTask = null; private SwipeRefreshLayout mSwipeContainer; private RecyclerView mRecyclerView; private ContentViewAdapter adapter; private LinearLayout content_view_linear_layout; private TextView content_view_title, content_view_time; private WebView content_view_content_detail; private String course_id, content_id; private String currentDownloadUrl = ""; private String currentDownloadFileName = ""; static public String folder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_content_view); setTitle(getIntent().getStringExtra("Title")); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } course_id = getIntent().getStringExtra("CourseId"); content_id = getIntent().getStringExtra("content_id"); mRecyclerView = findViewById(R.id.recycler_content_view_list); mSwipeContainer = findViewById(R.id.content_view_swipe_container); content_view_linear_layout = findViewById(R.id.content_view_linear_layout); content_view_title = findViewById(R.id.content_view_title); content_view_time = findViewById(R.id.content_view_time); content_view_content_detail = findViewById(R.id.content_view_content_detail); adapter = new ContentViewAdapter(new ArrayList<AttachedFileItem>(), this); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(adapter); mSwipeContainer.setOnRefreshListener(this); mSwipeContainer.setColorSchemeColors(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorAccent)); showLoading(true); mLoadingTask = new AttachedFilesListLoadingTask(); mLoadingTask.execute((Void) null); Slidr.attach(this); SharedPreferences sharedPreferences = getSharedPreferences("login_info", Context.MODE_PRIVATE); folder = sharedPreferences.getString("path_preference", null); } @Override public void onRefresh() { if (mLoadingTask == null) { mLoadingTask = new AttachedFilesListLoadingTask(); mLoadingTask.execute((Void) null); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; } return (super.onOptionsItemSelected(item)); } @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) private void showLoading(final boolean show) { // 逐渐显示mRecyclerView的小动画 int shortAnimTime = 200; content_view_linear_layout.setVisibility(show ? View.GONE : View.VISIBLE); content_view_linear_layout.animate().setDuration(shortAnimTime).alpha( show ? 0 : 1).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mRecyclerView.setVisibility(show ? View.GONE : View.VISIBLE); } }); mSwipeContainer.setRefreshing(show); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // Forward results to EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) { new DownloadFile().execute(); } @Override public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) { } public void startDownload(AttachedFileItem item) { currentDownloadUrl = item.getUrl(); currentDownloadFileName = item.getFileName(); if (item.isDownloaded()) { openFile(folder + currentDownloadFileName); return; } //check if app has permission to write to the external storage. if (EasyPermissions.hasPermissions(ContentViewActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { //Get the URL entered new DownloadFile().execute(); } else { //If permission is not present request for the same. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { EasyPermissions.requestPermissions(ContentViewActivity.this, "PKU Courses是开源软件,绝不会滥用权限。请授权存储权限以下载文件。", WRITE_REQUEST_CODE, Manifest.permission.WRITE_EXTERNAL_STORAGE); } } } private void openFile(String filePath) { final Uri data = FileProvider.getUriForFile(getApplicationContext(), "edu_cn.pku.course", new File(filePath)); grantUriPermission(getPackageName(), data, Intent.FLAG_GRANT_READ_URI_PERMISSION); MimeTypeMap myMime = MimeTypeMap.getSingleton(); Intent newIntent = new Intent(Intent.ACTION_VIEW); String mimeType = myMime.getMimeTypeFromExtension(fileExt(filePath)); newIntent.setDataAndType(data, mimeType); newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); newIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); try { startActivity(newIntent); } catch (ActivityNotFoundException e) { Toast.makeText(getApplicationContext(), "No handler for this type of file.", Toast.LENGTH_LONG).show(); } } public Drawable getIcon(String fileName) { final Intent innt = new Intent(Intent.ACTION_VIEW); MimeTypeMap myMime = MimeTypeMap.getSingleton(); String mimeType = myMime.getMimeTypeFromExtension(fileExt(fileName)); innt.setType(mimeType); final List<ResolveInfo> matches = getPackageManager().queryIntentActivities(innt, 0); if (matches.size() == 0) return null; return matches.get(0).loadIcon(getPackageManager()); } @NonNull private String fileExt(String url) { if (url.contains("?")) { url = url.substring(0, url.indexOf("?")); } if (url.lastIndexOf(".") == -1) { return "."; } else { String ext = url.substring(url.lastIndexOf(".") + 1); if (ext.contains("%")) { ext = ext.substring(0, ext.indexOf("%")); } if (ext.contains("/")) { ext = ext.substring(0, ext.indexOf("/")); } return ext.toLowerCase(); } } /** * Async Task to download file from URL */ @SuppressLint("StaticFieldLeak") private class DownloadFile extends AsyncTask<Void, String, String> { private ProgressDialog progressDialog; private String fileName; // private boolean isDownloaded; /** * Before starting background thread * Show Progress Bar Dialog */ @Override protected void onPreExecute() { super.onPreExecute(); this.progressDialog = new ProgressDialog(ContentViewActivity.this, R.style.AlertDialogTheme); this.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); this.progressDialog.setCancelable(false); this.progressDialog.show(); } /** * Downloading file in background thread */ @Override protected String doInBackground(Void... params) { int count; try { SharedPreferences sharedPreferences = getSharedPreferences("login_info", Context.MODE_PRIVATE); String session_id = sharedPreferences.getString("session_id", null); URL url = new URL(currentDownloadUrl); URLConnection connection = url.openConnection(); connection.setRequestProperty("Cookie", "session_id=" + session_id); connection.connect(); // getting file length int lengthOfFile = connection.getContentLength(); // input stream to read file - with 8k buffer InputStream input = new BufferedInputStream(connection.getInputStream(), 8192); fileName = currentDownloadFileName; //External directory path to save file //folder = Utils.downloadFolder; //Create androiddeft folder if it does not exist File directory = new File(folder); if (!directory.exists()) { if (!directory.mkdirs()) { throw new Exception("Error creating folder"); } } // Output stream to write file OutputStream output = new FileOutputStream(folder + fileName); byte data[] = new byte[1024]; long total = 0; while ((count = input.read(data)) != -1) { total += count; // publishing the progress.... // After this onProgressUpdate will be called publishProgress("" + (int) ((total * 100) / lengthOfFile)); // writing data to file output.write(data, 0, count); } // flushing output output.flush(); // closing streams output.close(); input.close(); return folder + fileName; } catch (Exception e) { return Utils.errorPrefix + e.getMessage(); } } /** * Updating progress bar */ protected void onProgressUpdate(String... progress) { // setting progress percentage progressDialog.setProgress(Integer.parseInt(progress[0])); } @Override protected void onPostExecute(String message) { // dismiss the dialog after the file was downloaded this.progressDialog.dismiss(); if (message.startsWith(Utils.errorPrefix)) { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); return; } Toast.makeText(getApplicationContext(), "File downloaded at: " + message, Toast.LENGTH_LONG).show(); // Display File path after downloading // Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); adapter.refreshList(); // 刷新已下载文件 openFile(message); } } @SuppressLint("StaticFieldLeak") private class AttachedFilesListLoadingTask extends AsyncTask<Void, Void, String> { AttachedFilesListLoadingTask() { } @Override protected String doInBackground(Void... params) { return Utils.courseHttpGetRequest("http://course.pku.edu.cn/webapps/Bb-mobile-bb_bb60/contentDetail?course_id=" + course_id + "&content_id=" + content_id); } @Override protected void onPostExecute(final String str) { // 出现了错误 if (str.startsWith(Utils.errorPrefix)) { if (str.equals(Utils.errorPrefix + Utils.errorPasswordIncorrect)) { // 密码错误 Utils.SignOut(ContentViewActivity.this); } else { // 其他网络错误 Snackbar.make(mRecyclerView, str, Snackbar.LENGTH_SHORT).show(); } } else { Node rootNode = Utils.stringToNode(str); if (rootNode != null) { Element contentNode = (Element) rootNode.getFirstChild(); if (contentNode != null) { content_view_title.setText((contentNode).getAttribute("title")); try { content_view_time.setText( new SimpleDateFormat("yyyy年M月d日 H:m:s", Locale.CHINA) .format( new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz", Locale.US) .parse(contentNode.getAttribute("datemodified")) ) ); } catch (ParseException e) { content_view_time.setText(contentNode.getAttribute("datemodified")); } if (contentNode.getAttribute("contenthandler").equals("resource/x-bb-externallink")) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(contentNode.getAttribute("viewUrl"))); startActivity(browserIntent); finish(); } if (contentNode.getAttribute("contenthandler").equals("resource/x-bb-assignment")) { Intent intent = new Intent(ContentViewActivity.this, WebViewActivity.class); intent.putExtra("Title", contentNode.getAttribute("title")); intent.putExtra("WebViewUrl", contentNode.getAttribute("viewUrl")); startActivity(intent); finish(); } if ((contentNode).getElementsByTagName("body").getLength() > 0 && contentNode.getElementsByTagName("body").item(0).getFirstChild() != null) { content_view_content_detail.getSettings().setDefaultTextEncodingName("UTF-8"); content_view_content_detail.loadData( ((CharacterData) contentNode.getElementsByTagName("body").item(0).getFirstChild()).getData() , "text/html; charset=utf-8", null); content_view_content_detail.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith("http://course.pku.edu.cn")) { Intent intent = new Intent(ContentViewActivity.this, WebViewActivity.class); intent.putExtra("Title", "正在打开链接..."); intent.putExtra("WebViewUrl", url.replaceFirst("http://course.pku.edu.cn", "")); startActivity(intent); } else { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent); } return true; } }); } else { content_view_content_detail.setVisibility(View.GONE); } if ((contentNode).getElementsByTagName("attachments").getLength() > 0) { ArrayList<AttachedFileItem> item_list = new ArrayList<>(); NodeList nList = (contentNode).getElementsByTagName("attachments").item(0).getChildNodes(); for (int i = 0; i < nList.getLength(); i++) { item_list.add(new AttachedFileItem((Element) nList.item(i))); } adapter.updateList(item_list); } } } } mLoadingTask = null; showLoading(false); mSwipeContainer.setEnabled(false); } // 没什么用的函数 @Override protected void onCancelled() { mLoadingTask = null; showLoading(false); } } public class AttachedFileItem { Element n; boolean downloaded = false; AttachedFileItem(Element n) { this.n = n; } public boolean isDownloaded() { return downloaded; } public void setDownloaded(boolean b) { downloaded = b; } public String getFileName() { return n.getAttribute("name"); } public String getFileSize() { return Utils.readableFileSize(Integer.parseInt(n.getAttribute("filesize"))); } public int getFileSizeInteger() { return Integer.parseInt(n.getAttribute("filesize")); } private String getUrl() { return "http://course.pku.edu.cn" + n.getAttribute("uri"); } } }