diff --git a/app/build.gradle b/app/build.gradle
index 40becbad4..5a4a46918 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -25,6 +25,8 @@ dependencies {
compile 'com.android.support:support-v4:25.3.1'
compile 'com.loopj.android:android-async-http:1.4.9'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
- compile 'com.evernote:android-job:1.1.10'
+ compile 'com.evernote:android-job:1.1.11'
+ compile 'com.github.bumptech.glide:glide:4.0.0-RC1'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC1'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2217adfa..960322524 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -75,6 +75,12 @@
android:launchMode="singleTask"
android:noHistory="true"
/>
+
. */
+package fr.gouv.etalab.mastodon.activities;
+
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.URLUtil;
+import android.widget.ImageView;
+import android.widget.MediaController;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.VideoView;
+
+import com.loopj.android.http.AsyncHttpClient;
+import com.loopj.android.http.FileAsyncHttpResponseHandler;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
+import com.nostra13.universalimageloader.core.ImageLoader;
+import com.nostra13.universalimageloader.core.assist.FailReason;
+import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
+import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
+
+import java.io.File;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+
+import cz.msebera.android.httpclient.Header;
+import fr.gouv.etalab.mastodon.client.Entities.Attachment;
+import fr.gouv.etalab.mastodon.client.MastalabSSLSocketFactory;
+import fr.gouv.etalab.mastodon.helper.Helper;
+import mastodon.etalab.gouv.fr.mastodon.R;
+
+import static fr.gouv.etalab.mastodon.helper.Helper.EXTERNAL_STORAGE_REQUEST_CODE;
+
+
+/**
+ * Created by Thomas on 25/06/2017.
+ * Media Activity
+ */
+
+public class MediaActivity extends AppCompatActivity {
+
+
+ private RelativeLayout loader;
+ private ArrayList attachments;
+ private ImageView imageView;
+ private VideoView videoView;
+ private float downX, downY;
+ private int mediaPosition;
+ MediaActivity.actionSwipe currentAction;
+ private ImageLoader imageLoader;
+ private DisplayImageOptions options;
+ static final int MIN_DISTANCE = 200;
+ private String finalUrlDownload;
+ private ImageView prev, next;
+ private boolean isHiding;
+ private Bitmap downloadedImage;
+ private File fileVideo;
+ private TextView progress;
+ private enum actionSwipe{
+ RIGHT_TO_LEFT,
+ LEFT_TO_RIGHT,
+ POP
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_media);
+ attachments = getIntent().getParcelableArrayListExtra("mediaArray");
+ mediaPosition = getIntent().getExtras().getInt("position", 1);
+ if( attachments == null || attachments.size() == 0)
+ finish();
+ if( getSupportActionBar() != null)
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ loader = (RelativeLayout) findViewById(R.id.loader);
+ imageView = (ImageView) findViewById(R.id.media_picture);
+ videoView = (VideoView) findViewById(R.id.media_video);
+ prev = (ImageView) findViewById(R.id.media_prev);
+ next = (ImageView) findViewById(R.id.media_next);
+ prev.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mediaPosition--;
+ displayMediaAtPosition(actionSwipe.POP);
+ }
+ });
+ next.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mediaPosition++;
+ displayMediaAtPosition(actionSwipe.POP);
+ }
+ });
+
+ progress = (TextView) findViewById(R.id.loader_progress);
+ setTitle("");
+ final ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout); // Your own view, read class comments
+
+ isHiding = false;
+ imageLoader = ImageLoader.getInstance();
+ options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
+ .cacheOnDisk(true).resetViewBeforeLoading(true).build();
+ setTitle("");
+ displayMediaAtPosition(actionSwipe.POP);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ case R.id.action_download:
+ if(Build.VERSION.SDK_INT >= 23 ){
+ if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
+ ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_REQUEST_CODE);
+ } else {
+ Helper.manageMoveFileDownload(MediaActivity.this, finalUrlDownload, downloadedImage, fileVideo);
+ }
+ }else{
+ Helper.manageMoveFileDownload(MediaActivity.this, finalUrlDownload, downloadedImage, fileVideo);
+ }
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main_media, menu);
+ return true;
+ }
+
+
+
+ /**
+ * Manage touch event
+ * Allows to swipe from timelines
+ * @param event MotionEvent
+ * @return boolean
+ */
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ if( mediaPosition > attachments.size() || mediaPosition < 1 || attachments.size() <= 1)
+ return super.dispatchTouchEvent(event);
+ switch(event.getAction()){
+ case MotionEvent.ACTION_DOWN: {
+ downX = event.getX();
+ downY = event.getY();
+ //Displays navigation left/right buttons
+ if( attachments != null && attachments.size() > 1 && !isHiding){
+ prev.setVisibility(View.VISIBLE);
+ next.setVisibility(View.VISIBLE);
+ isHiding = true;
+ new Handler().postDelayed(new Runnable(){
+ public void run() {
+ prev.setVisibility(View.GONE);
+ next.setVisibility(View.GONE);
+ isHiding = false;
+ }
+ }, 1000);
+ }
+ return super.dispatchTouchEvent(event);
+ }
+ case MotionEvent.ACTION_UP: {
+ float upX = event.getX();
+ float upY = event.getY();
+ float deltaX = downX - upX;
+ float deltaY = downY - upY;
+ // swipe horizontal
+ if( downX > MIN_DISTANCE & (Math.abs(deltaX) > MIN_DISTANCE && Math.abs(deltaY) < MIN_DISTANCE)){
+ if(deltaX < 0) { switchOnSwipe(MediaActivity.actionSwipe.LEFT_TO_RIGHT); return true; }
+ if(deltaX > 0) { switchOnSwipe(MediaActivity.actionSwipe.RIGHT_TO_LEFT); return true; }
+ }else{
+ currentAction = MediaActivity.actionSwipe.POP;
+ }
+ }
+ }
+ return super.dispatchTouchEvent(event);
+ }
+
+
+ private void switchOnSwipe(actionSwipe action){
+ loader.setVisibility(View.VISIBLE);
+ mediaPosition = (action == actionSwipe.LEFT_TO_RIGHT)?mediaPosition-1:mediaPosition+1;
+ displayMediaAtPosition(action);
+ }
+
+ private void displayMediaAtPosition(actionSwipe action){
+ if( mediaPosition > attachments.size() )
+ mediaPosition = 1;
+ if( mediaPosition < 1)
+ mediaPosition = attachments.size();
+ currentAction = action;
+ Attachment attachment = attachments.get(mediaPosition-1);
+ String type = attachment.getType();
+ final String url = attachment.getUrl();
+ finalUrlDownload = url;
+ videoView.setVisibility(View.GONE);
+ if( videoView.isPlaying()) {
+ videoView.stopPlayback();
+ }
+ imageView.setVisibility(View.GONE);
+
+ switch (type){
+ case "image":
+ imageLoader.displayImage(url, imageView, options, new SimpleImageLoadingListener(){
+ @Override
+ public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
+ super.onLoadingComplete(imageUri, view, loadedImage);
+ loader.setVisibility(View.GONE);
+ imageView.setVisibility(View.VISIBLE);
+ downloadedImage = loadedImage;
+ fileVideo = null;
+ }
+ @Override
+ public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
+ imageLoader.displayImage(url, imageView, options);
+ loader.setVisibility(View.GONE);
+ }
+ });
+ break;
+ case "video":
+ case "gifv":
+ AsyncHttpClient client = new AsyncHttpClient();
+ MastalabSSLSocketFactory mastalabSSLSocketFactory;
+ try {
+ mastalabSSLSocketFactory = new MastalabSSLSocketFactory(MastalabSSLSocketFactory.getKeystore());
+ mastalabSSLSocketFactory.setHostnameVerifier(MastalabSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ client.setSSLSocketFactory(mastalabSSLSocketFactory);
+ File file = new File(getCacheDir() + "/" + Helper.md5(url)+".mp4");
+ if(file.exists()) {
+ Uri uri = Uri.parse(file.getAbsolutePath());
+ videoView.setVisibility(View.VISIBLE);
+ videoView.setVideoURI(uri);
+ videoView.start();
+ MediaController mc = new MediaController(MediaActivity.this);
+ videoView.setMediaController(mc);
+ videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ loader.setVisibility(View.GONE);
+ }
+ });
+ videoView.setVisibility(View.VISIBLE);
+ fileVideo = file;
+ downloadedImage = null;
+ }else{
+ progress.setText("0 %");
+ progress.setVisibility(View.VISIBLE);
+ client.get(url, new FileAsyncHttpResponseHandler(/* Context */ this) {
+ @Override
+ public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {
+ progress.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onProgress(long bytesWritten, long totalSize) {
+ long progressPercentage = (long)100*bytesWritten/totalSize;
+ progress.setText(String.valueOf(progressPercentage) + " %");
+ }
+
+ @Override
+ public void onSuccess(int statusCode, Header[] headers, File response) {
+ File dir = getCacheDir();
+ File from = new File(dir, response.getName());
+ File to = new File(dir, Helper.md5(url) + ".mp4");
+ if (from.exists())
+ from.renameTo(to);
+ fileVideo = to;
+ downloadedImage = null;
+ progress.setVisibility(View.GONE);
+ Uri uri = Uri.parse(to.getAbsolutePath());
+ videoView.setVisibility(View.VISIBLE);
+ videoView.setVideoURI(uri);
+ videoView.start();
+ MediaController mc = new MediaController(MediaActivity.this);
+ videoView.setMediaController(mc);
+ videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ loader.setVisibility(View.GONE);
+ }
+ });
+ videoView.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+ } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | UnrecoverableKeyException e) {
+ e.printStackTrace();
+ }
+ break;
+ }
+ String filename = URLUtil.guessFileName(url, null, null);
+ if( filename == null)
+ filename = url;
+ LayoutInflater mInflater = LayoutInflater.from(MediaActivity.this);
+ ActionBar actionBar = getSupportActionBar();
+ if( actionBar != null){
+ View picture_actionbar = mInflater.inflate(R.layout.picture_actionbar, null);
+ TextView picture_actionbar_title = (TextView) picture_actionbar.findViewById(R.id.picture_actionbar);
+ picture_actionbar_title.setText(filename);
+ actionBar.setCustomView(picture_actionbar);
+ actionBar.setDisplayShowCustomEnabled(true);
+ }else {
+ setTitle(url);
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java
index c6a23b667..4f0dec6b2 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java
@@ -97,7 +97,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
private ImageLoader imageLoader;
private DisplayImageOptions options;
private LinearLayout toot_picture_container;
- private List attachments;
+ private ArrayList attachments;
private boolean isSensitive = false;
private ImageButton toot_visibility;
private Button toot_it;
@@ -107,7 +107,7 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
private ListView toot_lv_accounts;
private BroadcastReceiver search_validate;
private Status tootReply = null;
- private String sharedContent, sharedSubject, sharedTitle;
+ private String sharedContent, sharedSubject;
private CheckBox toot_sensitive;
private String pattern = "^.*(@([a-zA-Z0-9_]{2,}))$";
@@ -139,7 +139,6 @@ public class TootActivity extends AppCompatActivity implements OnRetrieveSearcAc
tootReply = b.getParcelable("tootReply");
sharedContent = b.getString("sharedContent", null);
sharedSubject = b.getString("sharedSubject", null);
- sharedTitle = b.getString("sharedTitle", null);
}
if( tootReply != null) {
setTitle(R.string.toot_title_reply);
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewActivity.java
index 08427efc7..2bc6edba2 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewActivity.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewActivity.java
@@ -15,32 +15,19 @@
package fr.gouv.etalab.mastodon.activities;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
-
-import android.media.MediaPlayer;
-import android.os.Build;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.view.LayoutInflater;
+import android.util.Log;
import android.view.MenuItem;
-import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.webkit.CookieManager;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
import android.webkit.WebView;
-import android.webkit.WebViewClient;
import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
import fr.gouv.etalab.mastodon.helper.Helper;
+import fr.gouv.etalab.mastodon.webview.MastalabWebChromeClient;
+import fr.gouv.etalab.mastodon.webview.MastalabWebViewClient;
import mastodon.etalab.gouv.fr.mastodon.R;
@@ -52,8 +39,7 @@ import mastodon.etalab.gouv.fr.mastodon.R;
public class WebviewActivity extends AppCompatActivity {
private String url;
- private ProgressBar pbar;
- private static boolean isVideoFullscreen;
+
@Override
@@ -67,48 +53,15 @@ public class WebviewActivity extends AppCompatActivity {
finish();
if( getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
- boolean javascript = sharedpreferences.getBoolean(Helper.SET_JAVASCRIPT, true);
-
-
-
- pbar = (ProgressBar) findViewById(R.id.progress_bar);
- WebView webView = (WebView) findViewById(R.id.webview);
- webView.getSettings().setJavaScriptEnabled(javascript);
- webView.getSettings().setUseWideViewPort(true);
- webView.getSettings().setLoadWithOverviewMode(true);
- webView.getSettings().setSupportZoom(true);
- webView.getSettings().setDisplayZoomControls(false);
- webView.getSettings().setBuiltInZoomControls(true);
- webView.getSettings().setAllowContentAccess(true);
- webView.getSettings().setLoadsImagesAutomatically(true);
- webView.getSettings().setSupportMultipleWindows(false);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
- //noinspection deprecation
- webView.getSettings().setPluginState(WebSettings.PluginState.ON);
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- webView.getSettings().setMediaPlaybackRequiresUserGesture(true);
- }
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- boolean cookies = sharedpreferences.getBoolean(Helper.SET_COOKIES, false);
- CookieManager cookieManager = CookieManager.getInstance();
- cookieManager.setAcceptThirdPartyCookies(webView, cookies);
- }
- webView.getSettings().setAppCacheEnabled(true);
- webView.getSettings().setDatabaseEnabled(true);
- webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
+ WebView webView = Helper.initializeWebview(WebviewActivity.this, R.id.webview);
setTitle("");
FrameLayout webview_container = (FrameLayout) findViewById(R.id.webview_container);
final ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout); // Your own view, read class comments
- MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient(webView, webview_container, videoLayout);
- mastalabWebChromeClient.setOnToggledFullscreen(new ToggledFullscreenCallback() {
+ MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient(WebviewActivity.this, webView, webview_container, videoLayout);
+ mastalabWebChromeClient.setOnToggledFullscreen(new MastalabWebChromeClient.ToggledFullscreenCallback() {
@Override
public void toggledFullscreen(boolean fullscreen) {
@@ -130,7 +83,7 @@ public class WebviewActivity extends AppCompatActivity {
}
});
webView.setWebChromeClient(mastalabWebChromeClient);
- webView.setWebViewClient(new MastalabWebViewClient());
+ webView.setWebViewClient(new MastalabWebViewClient(WebviewActivity.this));
webView.loadUrl(url);
}
@@ -147,208 +100,7 @@ public class WebviewActivity extends AppCompatActivity {
@Override
public void onDestroy(){
- isVideoFullscreen = false;
super.onDestroy();
}
-
- private class MastalabWebViewClient extends WebViewClient{
- @Override
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
- }
- @Override
- public void onPageStarted (WebView view, String url, Bitmap favicon) {
- super.onPageStarted(view, url, favicon);
- ActionBar actionBar = getSupportActionBar();
- LayoutInflater mInflater = LayoutInflater.from(WebviewActivity.this);
- if( actionBar != null){
- View webview_actionbar = mInflater.inflate(R.layout.webview_actionbar, null);
- TextView webview_title = (TextView) webview_actionbar.findViewById(R.id.webview_title);
- webview_title.setText(url);
- actionBar.setCustomView(webview_actionbar);
- actionBar.setDisplayShowCustomEnabled(true);
- }else {
- setTitle(url);
- }
- }
- }
-
- interface ToggledFullscreenCallback {
- void toggledFullscreen(boolean fullscreen);
- }
-
-
- private class MastalabWebChromeClient extends WebChromeClient implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
-
- private FrameLayout videoViewContainer;
- private CustomViewCallback videoViewCallback;
-
- private ToggledFullscreenCallback toggledFullscreenCallback;
-
- private WebView webView;
- private View activityNonVideoView;
- private ViewGroup activityVideoView;
-
- MastalabWebChromeClient(WebView webView, FrameLayout webviewContainer, ViewGroup videoLayout){
- isVideoFullscreen = false;
- this.webView = webView;
- this.activityNonVideoView = webviewContainer;
- this.activityVideoView = videoLayout;
- }
-
- @Override
- public void onProgressChanged(WebView view, int progress) {
- if (progress < 100 && pbar.getVisibility() == ProgressBar.GONE) {
- pbar.setVisibility(ProgressBar.VISIBLE);
- }
- pbar.setProgress(progress);
- if (progress == 100) {
- pbar.setVisibility(ProgressBar.GONE);
- }
- }
- @Override
- public void onReceivedIcon(WebView view, Bitmap icon) {
- super.onReceivedIcon(view, icon);
- LayoutInflater mInflater = LayoutInflater.from(WebviewActivity.this);
- ActionBar actionBar = getSupportActionBar();
- if( actionBar != null){
- View webview_actionbar = mInflater.inflate(R.layout.webview_actionbar, null);
- TextView webview_title = (TextView) webview_actionbar.findViewById(R.id.webview_title);
- webview_title.setText(view.getTitle());
- ImageView webview_favicon = (ImageView) webview_actionbar.findViewById(R.id.webview_favicon);
- if( icon != null)
- webview_favicon.setImageBitmap(icon);
- actionBar.setCustomView(webview_actionbar);
- actionBar.setDisplayShowCustomEnabled(true);
- }else {
- setTitle(view.getTitle());
- }
-
- }
-
- //FULLSCREEN VIDEO
- //Code from https://stackoverflow.com/a/16179544/3197259
-
- /**
- * Set a callback that will be fired when the video starts or finishes displaying using a custom view (typically full-screen)
- * @param callback A VideoEnabledWebChromeClient.ToggledFullscreenCallback callback
- */
- void setOnToggledFullscreen(ToggledFullscreenCallback callback) {
- this.toggledFullscreenCallback = callback;
- }
-
- @Override
- public void onShowCustomView(View view, CustomViewCallback callback) {
- if (view instanceof FrameLayout) {
- if( getSupportActionBar() != null)
- getSupportActionBar().hide();
- // A video wants to be shown
- FrameLayout frameLayout = (FrameLayout) view;
- View focusedChild = frameLayout.getFocusedChild();
-
- // Save video related variables
- isVideoFullscreen = true;
- this.videoViewContainer = frameLayout;
- this.videoViewCallback = callback;
-
- // Hide the non-video view, add the video view, and show it
- activityNonVideoView.setVisibility(View.INVISIBLE);
- activityVideoView.addView(videoViewContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- activityVideoView.setVisibility(View.VISIBLE);
- if (focusedChild instanceof android.widget.VideoView) {
- // android.widget.VideoView (typically API level <11)
- android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;
- // Handle all the required events
- videoView.setOnCompletionListener(this);
- videoView.setOnErrorListener(this);
- } else {
- // Other classes, including:
- // - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 11-18)
- // - android.webkit.HTML5VideoFullScreen$VideoTextureView, which inherits from android.view.TextureView (typically API level 11-18)
- // - com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 19+)
-
- // Handle HTML5 video ended event only if the class is a SurfaceView
- // Test case: TextureView of Sony Xperia T API level 16 doesn't work fullscreen when loading the javascript below
- if (webView != null && webView.getSettings().getJavaScriptEnabled() && focusedChild instanceof SurfaceView) {
- // Run javascript code that detects the video end and notifies the Javascript interface
- String js = "javascript:";
- js += "var _ytrp_html5_video_last;";
- js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
- js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";
- {
- js += "_ytrp_html5_video_last = _ytrp_html5_video;";
- js += "function _ytrp_html5_video_ended() {";
- {
- js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must match Javascript interface name and method of VideoEnableWebView
- }
- js += "}";
- js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
- }
- js += "}";
- webView.loadUrl(js);
- }
- }
- // Notify full-screen change
- if (toggledFullscreenCallback != null) {
- toggledFullscreenCallback.toggledFullscreen(true);
- }
- }
- }
-
- // Available in API level 14+, deprecated in API level 18+
- @Override @SuppressWarnings("deprecation")
- public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) {
- onShowCustomView(view, callback);
- }
-
- @Override
- public void onHideCustomView() {
- if( getSupportActionBar() != null)
- getSupportActionBar().show();
- // This method should be manually called on video end in all cases because it's not always called automatically.
- // This method must be manually called on back key press (from this class' onBackPressed() method).
- if (isVideoFullscreen) {
- // Hide the video view, remove it, and show the non-video view
- activityVideoView.setVisibility(View.INVISIBLE);
- activityVideoView.removeView(videoViewContainer);
- activityNonVideoView.setVisibility(View.VISIBLE);
- // Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)
- if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium.")) {
- videoViewCallback.onCustomViewHidden();
- }
-
- // Reset video related variables
- isVideoFullscreen = false;
- videoViewContainer = null;
- videoViewCallback = null;
-
- // Notify full-screen change
- if (toggledFullscreenCallback != null) {
- toggledFullscreenCallback.toggledFullscreen(false);
- }
- }
- }
-
- // Video will start loading
- @Override
- public View getVideoLoadingProgressView() {
- return super.getVideoLoadingProgressView();
- }
-
- // Video finished playing, only called in the case of android.widget.VideoView (typically API level <11)
- @Override
- public void onCompletion(MediaPlayer mp) {
- onHideCustomView();
- }
-
- // Error while playing video, only called in the case of android.widget.VideoView (typically API level <11)
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- return false; // By returning false, onCompletion() will be called
- }
-
- }
-
-
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
index 0e1e6122c..7bd78f251 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java
@@ -1160,7 +1160,7 @@ public class API {
//Retrieves attachments
JSONArray arrayAttachement = resobj.getJSONArray("media_attachments");
- List attachments = new ArrayList<>();
+ ArrayList attachments = new ArrayList<>();
if( arrayAttachement != null){
for(int j = 0 ; j < arrayAttachement.length() ; j++){
JSONObject attObj = arrayAttachement.getJSONObject(j);
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Attachment.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Attachment.java
index ee9eb771b..dd662371c 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Attachment.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Attachment.java
@@ -14,11 +14,15 @@
* see . */
package fr.gouv.etalab.mastodon.client.Entities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
/**
* Created by Thomas on 23/04/2017.
+ * Manages Media
*/
-public class Attachment {
+public class Attachment implements Parcelable {
private String id;
private String type;
@@ -27,6 +31,31 @@ public class Attachment {
private String preview_url;
private String text_url;
+ public Attachment(Parcel in) {
+ id = in.readString();
+ type = in.readString();
+ url = in.readString();
+ remote_url = in.readString();
+ preview_url = in.readString();
+ text_url = in.readString();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public Attachment createFromParcel(Parcel in) {
+ return new Attachment(in);
+ }
+
+ @Override
+ public Attachment[] newArray(int size) {
+ return new Attachment[size];
+ }
+ };
+
+ public Attachment() {
+
+ }
+
public String getId() {
return id;
}
@@ -74,4 +103,19 @@ public class Attachment {
public void setText_url(String text_url) {
this.text_url = text_url;
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(id);
+ dest.writeString(type);
+ dest.writeString(url);
+ dest.writeString(remote_url);
+ dest.writeString(preview_url);
+ dest.writeString(text_url);
+ }
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java
index 8f6c609b1..f30a9872e 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java
@@ -18,6 +18,7 @@ package fr.gouv.etalab.mastodon.client.Entities;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -46,7 +47,7 @@ public class Status implements Parcelable {
private String visibility;
private boolean attachmentShown = false;
private boolean spoilerShown = false;
- private List media_attachments;
+ private ArrayList media_attachments;
private List mentions;
private List tags;
private Application application;
@@ -208,11 +209,11 @@ public class Status implements Parcelable {
}
- public List getMedia_attachments() {
+ public ArrayList getMedia_attachments() {
return media_attachments;
}
- public void setMedia_attachments(List media_attachments) {
+ public void setMedia_attachments(ArrayList media_attachments) {
this.media_attachments = media_attachments;
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java
index 5bad28fba..e6f7aa02e 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java
@@ -14,7 +14,6 @@ package fr.gouv.etalab.mastodon.drawers;
* You should have received a copy of the GNU General Public License along with Thomas Schneider; if not,
* see . */
-import android.Manifest;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -22,21 +21,15 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.media.MediaPlayer;
-import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.webkit.WebView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
@@ -46,18 +39,15 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.VideoView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
-import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
-import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.util.ArrayList;
import java.util.List;
-import fr.gouv.etalab.mastodon.activities.MainActivity;
+import fr.gouv.etalab.mastodon.activities.MediaActivity;
import fr.gouv.etalab.mastodon.activities.ShowConversationActivity;
import fr.gouv.etalab.mastodon.activities.TootActivity;
import fr.gouv.etalab.mastodon.client.Entities.Error;
@@ -71,7 +61,6 @@ import fr.gouv.etalab.mastodon.client.Entities.Attachment;
import fr.gouv.etalab.mastodon.client.Entities.Status;
import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface;
-import static fr.gouv.etalab.mastodon.helper.Helper.EXTERNAL_STORAGE_REQUEST_CODE;
/**
@@ -463,6 +452,7 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
}else {
holder.status_prev4_container.setVisibility(View.VISIBLE);
}
+ int position = 1;
for(final Attachment attachment: attachments){
ImageView imageView;
if( i == 0) {
@@ -496,13 +486,20 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
if( url.trim().contains("missing.png"))
continue;
imageLoader.displayImage(url, imageView, options);
+ final int finalPosition = position;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- showPicture(attachment);
+ Intent intent = new Intent(context, MediaActivity.class);
+ Bundle b = new Bundle();
+ intent.putParcelableArrayListExtra("mediaArray", status.getMedia_attachments());
+ b.putInt("position", finalPosition);
+ intent.putExtras(b);
+ context.startActivity(intent);
}
});
i++;
+ position++;
}
holder.status_document_container.setVisibility(View.VISIBLE);
}else{
@@ -511,101 +508,6 @@ public class StatusListAdapter extends BaseAdapter implements OnPostActionInterf
holder.status_show_more.setVisibility(View.GONE);
}
- private void showPicture(final Attachment attachment) {
-
- final AlertDialog.Builder alertadd = new AlertDialog.Builder(context);
- LayoutInflater factory = LayoutInflater.from(context);
- final View view = factory.inflate(R.layout.show_attachment, null);
- alertadd.setView(view);
- final RelativeLayout loader = (RelativeLayout) view.findViewById(R.id.loader);
- switch (attachment.getType()){
- case "image": {
- String url = attachment.getPreview_url();
- if(url == null || url.trim().equals(""))
- url = attachment.getUrl();
- final ImageView imageView = (ImageView) view.findViewById(R.id.dialog_imageview);
- imageLoader.displayImage(url, imageView, options, new SimpleImageLoadingListener(){
- @Override
- public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
- super.onLoadingComplete(imageUri, view, loadedImage);
- loader.setVisibility(View.GONE);
- imageView.setVisibility(View.VISIBLE);
- }
- @Override
- public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
- imageLoader.displayImage(attachment.getPreview_url(), imageView, options);
- loader.setVisibility(View.GONE);
- }
- });
- break;
- }
- case "gifv":
- case "video": {
- if( attachment.getRemote_url().contains(".gif") ){
- view.findViewById(R.id.dialog_webview_container).setVisibility(View.VISIBLE);
- WebView webView = (WebView) view.findViewById(R.id.dialog_webview);
- webView.getSettings().setJavaScriptEnabled(false);
- webView.clearCache(false);
- webView.setScrollbarFadingEnabled(true);
- webView.getSettings().setBuiltInZoomControls(false);
- webView.getSettings().setSupportZoom(false);
- webView.getSettings().setUseWideViewPort(false);
- webView.setVerticalScrollBarEnabled(false);
- webView.setHorizontalScrollBarEnabled(false);
- webView.setInitialScale(0);
- String url = attachment.getRemote_url();
- if(url == null || url.trim().equals(""))
- url = attachment.getUrl();
- webView.loadUrl(url);
- loader.setVisibility(View.GONE);
- }else {
- String url = attachment.getRemote_url();
- if(url == null || url.trim().equals(""))
- url = attachment.getUrl();
- Uri uri = Uri.parse(url);
- VideoView videoView = (VideoView) view.findViewById(R.id.dialog_videoview);
- videoView.setVisibility(View.VISIBLE);
- videoView.setVideoURI(uri);
- videoView.start();
- videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mp) {
- loader.setVisibility(View.GONE);
- }
- });
- }
-
- break;
- }
- }
- String urlDownload = attachment.getRemote_url();
- if( urlDownload == null || urlDownload.trim().equals(""))
- urlDownload = attachment.getUrl();
- final String finalUrlDownload = urlDownload;
- alertadd.setPositiveButton(R.string.download, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dlg, int sumthin) {
- if(Build.VERSION.SDK_INT >= 23 ){
- if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
- ActivityCompat.requestPermissions((MainActivity)context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_REQUEST_CODE);
- } else {
-
- Helper.manageDownloads(context, finalUrlDownload);
- }
- }else{
- Helper.manageDownloads(context, finalUrlDownload);
- }
- dlg.dismiss();
- }
- });
- alertadd.setNeutralButton(R.string.close, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dlg, int sumthin) {
- dlg.dismiss();
- }
- });
-
- alertadd.show();
- }
-
@Override
public void onPostAction(int statusCode, API.StatusAction statusAction, String targetedId, Error error) {
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java
index c1f8453b0..10d0d4ef6 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java
@@ -51,6 +51,10 @@ import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
+import android.webkit.CookieManager;
+import android.webkit.MimeTypeMap;
+import android.webkit.URLUtil;
+import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.TextView;
@@ -65,9 +69,12 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -75,6 +82,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Random;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -445,48 +453,94 @@ public class Helper {
}
+
+
+
+
/**
* Manage downloads with URLs
* @param context Context
* @param url String download url
*/
- public static void manageDownloads(final Context context, final String url){
+ public static void manageDownloads(final Context context, final String url, Bitmap bitmap){
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- final DownloadManager.Request request;
- try {
- request = new DownloadManager.Request(Uri.parse(url.trim()));
- }catch (Exception e){
- Toast.makeText(context,R.string.toast_error,Toast.LENGTH_LONG).show();
- return;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ final DownloadManager.Request request;
+ try {
+ request = new DownloadManager.Request(Uri.parse(url.trim()));
+ }catch (Exception e){
+ Toast.makeText(context,R.string.toast_error,Toast.LENGTH_LONG).show();
+ return;
+ }
+ final String fileName = URLUtil.guessFileName(url, null, null);
+ builder.setMessage(context.getResources().getString(R.string.download_file, fileName));
+ builder.setCancelable(false)
+ .setPositiveButton(context.getString(R.string.yes), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ request.allowScanningByMediaScanner();
+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
+ DownloadManager dm = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
+ dm.enqueue(request);
+ dialog.dismiss();
+ }
+
+ })
+ .setNegativeButton(context.getString(R.string.cancel), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ if( alert.getWindow() != null )
+ alert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ alert.show();
+ }else {
+ final String fileName = URLUtil.guessFileName(url, null, null);
+ File myDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ File file = new File (myDir, fileName);
+ try {
+ FileOutputStream out = new FileOutputStream(file);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
+ out.flush();
+ out.close();
+ Random r = new Random();
+ int notificationIdTmp = r.nextInt(10000);
+ // prepare intent which is triggered if the
+ // notification is selected
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
+ Intent intent = new Intent();
+ intent.setAction(android.content.Intent.ACTION_VIEW);
+ Uri uri = Uri.parse("file://" + file.getAbsolutePath());
+ intent.setDataAndType(uri, getMimeType(url));
+ final PendingIntent pIntentDownload = PendingIntent.getActivity(context, notificationIdTmp, intent, PendingIntent.FLAG_ONE_SHOT);
+
+ // build notification
+ // the addAction re-use the same intent to keep the example short
+ NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.ic_action_download)
+ .setTicker(context.getString(R.string.download_over))
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setContentIntent(pIntentDownload)
+ .setContentText(context.getString(R.string.download_from, fileName))
+ .setContentTitle(context.getString(R.string.download_over));
+ notificationManager.notify(notificationIdTmp, notificationBuilder.build());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
- Uri uri = Uri.parse(url);
- File f = new File("" + uri);
- final String fileName = f.getName();
- builder.setMessage(context.getResources().getString(R.string.download_file, fileName));
- builder.setCancelable(false)
- .setPositiveButton(context.getString(R.string.yes), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- request.allowScanningByMediaScanner();
- request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,fileName);
- request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
- DownloadManager dm = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
- dm.enqueue(request);
- dialog.dismiss();
- }
-
- })
- .setNegativeButton(context.getString(R.string.cancel), new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- if( alert.getWindow() != null )
- alert.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- alert.show();
}
+ private static String getMimeType(String url) {
+ String type = null;
+ String extension = MimeTypeMap.getFileExtensionFromUrl(url);
+ if (extension != null) {
+ type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ }
+ return type;
+ }
/**
* Sends notification with intent
@@ -522,6 +576,53 @@ public class Helper {
notificationManager.notify(notificationId, notificationBuilder.build());
}
+
+ /**
+ * Manage downloads with URLs
+ * @param context Context
+ * @param url String download url
+ */
+ public static void manageMoveFileDownload(final Context context, final String url, Bitmap bitmap, File fileVideo){
+
+ final String fileName = URLUtil.guessFileName(url, null, null);
+ File myDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+ File file = new File (myDir, fileName);
+ try {
+ if( bitmap != null) {
+ FileOutputStream out = new FileOutputStream(file);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
+ out.flush();
+ out.close();
+ }else{
+ file = fileVideo;
+ }
+ Random r = new Random();
+ int notificationIdTmp = r.nextInt(10000);
+ // prepare intent which is triggered if the
+ // notification is selected
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
+ Intent intent = new Intent();
+ intent.setAction(android.content.Intent.ACTION_VIEW);
+ Uri uri = Uri.parse("file://" + file.getAbsolutePath());
+ intent.setDataAndType(uri, getMimeType(url));
+ final PendingIntent pIntentDownload = PendingIntent.getActivity(context, notificationIdTmp, intent, PendingIntent.FLAG_ONE_SHOT);
+
+ // build notification
+ // the addAction re-use the same intent to keep the example short
+ NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.ic_action_download)
+ .setTicker(context.getString(R.string.download_over))
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setContentIntent(pIntentDownload)
+ .setContentText(context.getString(R.string.download_from, fileName))
+ .setContentTitle(context.getString(R.string.download_over));
+ notificationManager.notify(notificationIdTmp, notificationBuilder.build());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
/**
* Returns the instance of the authenticated user
* @param context Context
@@ -904,4 +1005,68 @@ public class Helper {
return statusTV;
}
+
+ public static WebView initializeWebview(Activity activity, int webviewId){
+
+ WebView webView = (WebView) activity.findViewById(webviewId);
+ final SharedPreferences sharedpreferences = activity.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
+ boolean javascript = sharedpreferences.getBoolean(Helper.SET_JAVASCRIPT, true);
+
+ webView.getSettings().setJavaScriptEnabled(javascript);
+ webView.getSettings().setUseWideViewPort(true);
+ webView.getSettings().setLoadWithOverviewMode(true);
+ webView.getSettings().setSupportZoom(true);
+ webView.getSettings().setDisplayZoomControls(false);
+ webView.getSettings().setBuiltInZoomControls(true);
+ webView.getSettings().setAllowContentAccess(true);
+ webView.getSettings().setLoadsImagesAutomatically(true);
+ webView.getSettings().setSupportMultipleWindows(false);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ //noinspection deprecation
+ webView.getSettings().setPluginState(WebSettings.PluginState.ON);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ webView.getSettings().setMediaPlaybackRequiresUserGesture(true);
+ }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ boolean cookies = sharedpreferences.getBoolean(Helper.SET_COOKIES, false);
+ CookieManager cookieManager = CookieManager.getInstance();
+ cookieManager.setAcceptThirdPartyCookies(webView, cookies);
+ }
+ webView.getSettings().setAppCacheEnabled(true);
+ webView.getSettings().setDatabaseEnabled(true);
+ webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
+
+ return webView;
+ }
+
+
+ public static String md5(final String s) {
+ final String MD5 = "MD5";
+ try {
+ // Create MD5 Hash
+ MessageDigest digest = java.security.MessageDigest
+ .getInstance(MD5);
+ digest.update(s.getBytes());
+ byte messageDigest[] = digest.digest();
+
+ // Create Hex String
+ StringBuilder hexString = new StringBuilder();
+ for (byte aMessageDigest : messageDigest) {
+ String h = Integer.toHexString(0xFF & aMessageDigest);
+ while (h.length() < 2)
+ h = "0" + h;
+ hexString.append(h);
+ }
+ return hexString.toString();
+
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java
index f198424e5..e5be2304c 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/HomeTimelineSyncJob.java
@@ -22,13 +22,18 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
+import android.view.View;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
+import com.nostra13.universalimageloader.core.assist.FailReason;
+import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
+import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.File;
import java.util.List;
@@ -124,13 +129,11 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe
List statuses = apiResponse.getStatuses();
if( apiResponse.getError() != null || statuses == null || statuses.size() == 0)
return;
- Bitmap icon_notification = null;
final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
- String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null);
+ final String max_id = sharedpreferences.getString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, null);
//No previous notifications in cache, so no notification will be sent
String message;
- String title = null;
for(Status status: statuses){
//The notification associated to max_id is discarded as it is supposed to have already been sent
@@ -138,41 +141,55 @@ public class HomeTimelineSyncJob extends Job implements OnRetrieveHomeTimelineSe
if( (max_id != null && status.getId().equals(max_id)) || status.getAccount().getAcct().trim().equals(acct.trim()))
continue;
String notificationUrl = status.getAccount().getAvatar();
- if( notificationUrl != null && icon_notification == null){
- try {
- ImageLoader imageLoaderNoty = ImageLoader.getInstance();
- File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name));
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext())
- .imageDownloader(new PatchBaseImageDownloader(getContext()))
- .threadPoolSize(5)
- .threadPriority(Thread.MIN_PRIORITY + 3)
- .denyCacheImageMultipleSizesInMemory()
- .diskCache(new UnlimitedDiskCache(cacheDir))
- .build();
- imageLoaderNoty.init(config);
- icon_notification = imageLoaderNoty.loadImageSync(notificationUrl);
- title = getContext().getResources().getString(R.string.notif_pouet, status.getAccount().getUsername());
- }catch (Exception e){
- icon_notification = BitmapFactory.decodeResource(getContext().getResources(),
- R.drawable.mastodonlogo);
- }
+
+ if(statuses.size() > 0 )
+ message = getContext().getResources().getQuantityString(R.plurals.other_notif_hometimeline, statuses.size(), statuses.size());
+ else
+ message = "";
+ final Intent intent = new Intent(getContext(), MainActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );
+ intent.putExtra(INTENT_ACTION, HOME_TIMELINE_INTENT);
+ intent.putExtra(PREF_KEY_ID, userId);
+ long notif_id = Long.parseLong(userId);
+ final int notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2);
+
+ SharedPreferences.Editor editor = sharedpreferences.edit();
+ editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getMax_id());
+ editor.apply();
+
+ if( notificationUrl != null){
+ ImageLoader imageLoaderNoty = ImageLoader.getInstance();
+ File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name));
+ ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext())
+ .imageDownloader(new PatchBaseImageDownloader(getContext()))
+ .threadPoolSize(5)
+ .threadPriority(Thread.MIN_PRIORITY + 3)
+ .denyCacheImageMultipleSizesInMemory()
+ .diskCache(new UnlimitedDiskCache(cacheDir))
+ .build();
+ imageLoaderNoty.init(config);
+ DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
+ .cacheOnDisk(true).resetViewBeforeLoading(true).build();
+ final String finalMessage = message;
+ final String finalTitle = getContext().getResources().getString(R.string.notif_pouet, status.getAccount().getUsername());
+ imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){
+ @Override
+ public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
+ super.onLoadingComplete(imageUri, view, loadedImage);
+ if( max_id != null)
+ notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, finalMessage);
+ }
+ @Override
+ public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
+ if( max_id != null)
+ notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
+ R.drawable.mastodonlogo), finalTitle, finalMessage);
+ }});
+
+
}
}
- if(statuses.size() > 0 )
- message = getContext().getResources().getQuantityString(R.plurals.other_notif_hometimeline, statuses.size(), statuses.size());
- else
- message = "";
- final Intent intent = new Intent(getContext(), MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );
- intent.putExtra(INTENT_ACTION, HOME_TIMELINE_INTENT);
- intent.putExtra(PREF_KEY_ID, userId);
- long notif_id = Long.parseLong(userId);
- int notificationId = ((notif_id + 2) > 2147483647) ? (int) (2147483647 - notif_id - 2) : (int) (notif_id + 2);
- if( max_id != null)
- notify_user(getContext(), intent, notificationId, icon_notification,title,message);
- SharedPreferences.Editor editor = sharedpreferences.edit();
- editor.putString(Helper.LAST_HOMETIMELINE_MAX_ID + userId, apiResponse.getMax_id());
- editor.apply();
+
}
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java
index fb97c1b49..28957237a 100644
--- a/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/jobs/NotificationsSyncJob.java
@@ -22,12 +22,19 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
+import android.view.View;
+
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
+import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
+import com.nostra13.universalimageloader.core.assist.FailReason;
+import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
+import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
+
import java.io.File;
import java.util.List;
import java.util.Set;
@@ -134,7 +141,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true);
boolean notif_mention = sharedpreferences.getBoolean(Helper.SET_NOTIF_MENTION, true);
boolean notif_share = sharedpreferences.getBoolean(Helper.SET_NOTIF_SHARE, true);
- String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId, null);
+ final String max_id = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId, null);
//No previous notifications in cache, so no notification will be sent
int newFollows = 0;
int newAdds = 0;
@@ -143,7 +150,7 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
int newShare = 0;
String notificationUrl = null;
String title = null;
- String message;
+ final String message;
for(Notification notification: notifications){
//The notification associated to max_id is discarded as it is supposed to have already been sent
if( max_id != null && notification.getId().equals(max_id))
@@ -187,24 +194,6 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
break;
default:
}
- if( notificationUrl != null && icon_notification == null){
- try {
- ImageLoader imageLoaderNoty = ImageLoader.getInstance();
- File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name));
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext())
- .imageDownloader(new PatchBaseImageDownloader(getContext()))
- .threadPoolSize(5)
- .threadPriority(Thread.MIN_PRIORITY + 3)
- .denyCacheImageMultipleSizesInMemory()
- .diskCache(new UnlimitedDiskCache(cacheDir))
- .build();
- imageLoaderNoty.init(config);
- icon_notification = imageLoaderNoty.loadImageSync(notificationUrl);
- }catch (Exception e){
- icon_notification = BitmapFactory.decodeResource(getContext().getResources(),
- R.drawable.mastodonlogo);
- }
- }
}
int allNotifCount = newFollows + newAdds + newAsks + newMentions + newShare;
if( allNotifCount > 0){
@@ -219,9 +208,38 @@ public class NotificationsSyncJob extends Job implements OnRetrieveNotifications
intent.putExtra(INTENT_ACTION, NOTIFICATION_INTENT);
intent.putExtra(PREF_KEY_ID, userId);
long notif_id = Long.parseLong(userId);
- int notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1);
- if( max_id != null)
- notify_user(getContext(), intent, notificationId, icon_notification,title,message);
+ final int notificationId = ((notif_id + 1) > 2147483647) ? (int) (2147483647 - notif_id - 1) : (int) (notif_id + 1);
+
+ if( notificationUrl != null && icon_notification == null){
+ ImageLoader imageLoaderNoty = ImageLoader.getInstance();
+ File cacheDir = new File(getContext().getCacheDir(), getContext().getString(R.string.app_name));
+ ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getContext())
+ .imageDownloader(new PatchBaseImageDownloader(getContext()))
+ .threadPoolSize(5)
+ .threadPriority(Thread.MIN_PRIORITY + 3)
+ .denyCacheImageMultipleSizesInMemory()
+ .diskCache(new UnlimitedDiskCache(cacheDir))
+ .build();
+ imageLoaderNoty.init(config);
+ DisplayImageOptions options = new DisplayImageOptions.Builder().displayer(new SimpleBitmapDisplayer()).cacheInMemory(false)
+ .cacheOnDisk(true).resetViewBeforeLoading(true).build();
+
+ final String finalTitle = title;
+ imageLoaderNoty.loadImage(notificationUrl, options, new SimpleImageLoadingListener(){
+ @Override
+ public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
+ super.onLoadingComplete(imageUri, view, loadedImage);
+ if( max_id != null)
+ notify_user(getContext(), intent, notificationId, loadedImage, finalTitle, message);
+ }
+ @Override
+ public void onLoadingFailed(java.lang.String imageUri, android.view.View view, FailReason failReason){
+ if( max_id != null)
+ notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
+ R.drawable.mastodonlogo), finalTitle, message);
+ }});
+ }
+
}
SharedPreferences.Editor editor = sharedpreferences.edit();
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebChromeClient.java b/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebChromeClient.java
new file mode 100644
index 000000000..d4f5edb80
--- /dev/null
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebChromeClient.java
@@ -0,0 +1,223 @@
+package fr.gouv.etalab.mastodon.webview;
+/* Copyright 2017 Thomas Schneider
+ *
+ * This file is a part of Mastodon Etalab for mastodon.etalab.gouv.fr
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Mastodon Etalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Thomas Schneider; if not,
+ * see . */
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.media.MediaPlayer;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import mastodon.etalab.gouv.fr.mastodon.R;
+
+/**
+ * Created by Thomas on 25/06/2017.
+ * Custom WebChromeClient
+ */
+
+public class MastalabWebChromeClient extends WebChromeClient implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
+
+ private FrameLayout videoViewContainer;
+ private WebChromeClient.CustomViewCallback videoViewCallback;
+
+ private ToggledFullscreenCallback toggledFullscreenCallback;
+
+ private WebView webView;
+ private View activityNonVideoView;
+ private ViewGroup activityVideoView;
+ private ProgressBar pbar;
+ private boolean isVideoFullscreen;
+ private Activity activity;
+
+
+ public interface ToggledFullscreenCallback {
+ void toggledFullscreen(boolean fullscreen);
+ }
+
+ public MastalabWebChromeClient(Activity activity, WebView webView, FrameLayout activityNonVideoView, ViewGroup activityVideoView){
+ this.activity = activity;
+ this.isVideoFullscreen = false;
+ this.webView = webView;
+ this.pbar = (ProgressBar) activity.findViewById(R.id.progress_bar);
+ this.activityNonVideoView = activityNonVideoView;
+ this.activityVideoView = activityVideoView;
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int progress) {
+ if( pbar != null){
+ if (progress < 100 && pbar.getVisibility() == ProgressBar.GONE) {
+ pbar.setVisibility(ProgressBar.VISIBLE);
+ }
+ pbar.setProgress(progress);
+ if (progress == 100) {
+ pbar.setVisibility(ProgressBar.GONE);
+ }
+ }
+ }
+
+
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ super.onReceivedIcon(view, icon);
+ LayoutInflater mInflater = LayoutInflater.from(activity);
+ ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
+ if( actionBar != null){
+ View webview_actionbar = mInflater.inflate(R.layout.webview_actionbar, null);
+ TextView webview_title = (TextView) webview_actionbar.findViewById(R.id.webview_title);
+ webview_title.setText(view.getTitle());
+ ImageView webview_favicon = (ImageView) webview_actionbar.findViewById(R.id.webview_favicon);
+ if( icon != null)
+ webview_favicon.setImageBitmap(icon);
+ actionBar.setCustomView(webview_actionbar);
+ actionBar.setDisplayShowCustomEnabled(true);
+ }else {
+ activity.setTitle(view.getTitle());
+ }
+
+ }
+
+ //FULLSCREEN VIDEO
+ //Code from https://stackoverflow.com/a/16179544/3197259
+
+ /**
+ * Set a callback that will be fired when the video starts or finishes displaying using a custom view (typically full-screen)
+ * @param callback A VideoEnabledWebChromeClient.ToggledFullscreenCallback callback
+ */
+ public void setOnToggledFullscreen(ToggledFullscreenCallback callback) {
+ this.toggledFullscreenCallback = callback;
+ }
+
+ @Override
+ public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
+ if (view instanceof FrameLayout) {
+ if( ((AppCompatActivity) activity).getSupportActionBar() != null)
+ ((AppCompatActivity) activity).getSupportActionBar().hide();
+ // A video wants to be shown
+ FrameLayout frameLayout = (FrameLayout) view;
+ View focusedChild = frameLayout.getFocusedChild();
+
+ // Save video related variables
+ isVideoFullscreen = true;
+ this.videoViewContainer = frameLayout;
+ this.videoViewCallback = callback;
+
+ // Hide the non-video view, add the video view, and show it
+ activityNonVideoView.setVisibility(View.INVISIBLE);
+ activityVideoView.addView(videoViewContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ activityVideoView.setVisibility(View.VISIBLE);
+ if (focusedChild instanceof android.widget.VideoView) {
+ // android.widget.VideoView (typically API level <11)
+ android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;
+ // Handle all the required events
+ videoView.setOnCompletionListener(this);
+ videoView.setOnErrorListener(this);
+ } else {
+ // Other classes, including:
+ // - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 11-18)
+ // - android.webkit.HTML5VideoFullScreen$VideoTextureView, which inherits from android.view.TextureView (typically API level 11-18)
+ // - com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 19+)
+
+ // Handle HTML5 video ended event only if the class is a SurfaceView
+ // Test case: TextureView of Sony Xperia T API level 16 doesn't work fullscreen when loading the javascript below
+ if (webView != null && webView.getSettings().getJavaScriptEnabled() && focusedChild instanceof SurfaceView) {
+ // Run javascript code that detects the video end and notifies the Javascript interface
+ String js = "javascript:";
+ js += "var _ytrp_html5_video_last;";
+ js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
+ js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";
+ {
+ js += "_ytrp_html5_video_last = _ytrp_html5_video;";
+ js += "function _ytrp_html5_video_ended() {";
+ {
+ js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must match Javascript interface name and method of VideoEnableWebView
+ }
+ js += "}";
+ js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
+ }
+ js += "}";
+ webView.loadUrl(js);
+ }
+ }
+ // Notify full-screen change
+ if (toggledFullscreenCallback != null) {
+ toggledFullscreenCallback.toggledFullscreen(true);
+ }
+ }
+ }
+
+ // Available in API level 14+, deprecated in API level 18+
+ @Override @SuppressWarnings("deprecation")
+ public void onShowCustomView(View view, int requestedOrientation, WebChromeClient.CustomViewCallback callback) {
+ onShowCustomView(view, callback);
+ }
+
+ @Override
+ public void onHideCustomView() {
+ if( ((AppCompatActivity) activity).getSupportActionBar() != null)
+ ((AppCompatActivity) activity).getSupportActionBar().show();
+ // This method should be manually called on video end in all cases because it's not always called automatically.
+ // This method must be manually called on back key press (from this class' onBackPressed() method).
+ if (isVideoFullscreen) {
+ // Hide the video view, remove it, and show the non-video view
+ activityVideoView.setVisibility(View.INVISIBLE);
+ activityVideoView.removeView(videoViewContainer);
+ activityNonVideoView.setVisibility(View.VISIBLE);
+ // Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)
+ if (videoViewCallback != null && !videoViewCallback.getClass().getName().contains(".chromium.")) {
+ videoViewCallback.onCustomViewHidden();
+ }
+
+ // Reset video related variables
+ isVideoFullscreen = false;
+ videoViewContainer = null;
+ videoViewCallback = null;
+
+ // Notify full-screen change
+ if (toggledFullscreenCallback != null) {
+ toggledFullscreenCallback.toggledFullscreen(false);
+ }
+ }
+ }
+
+ // Video will start loading
+ @Override
+ public View getVideoLoadingProgressView() {
+ return super.getVideoLoadingProgressView();
+ }
+
+ // Video finished playing, only called in the case of android.widget.VideoView (typically API level <11)
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ onHideCustomView();
+ }
+
+ // Error while playing video, only called in the case of android.widget.VideoView (typically API level <11)
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ return false; // By returning false, onCompletion() will be called
+ }
+
+}
+
diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebViewClient.java b/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebViewClient.java
new file mode 100644
index 000000000..9ff1d9348
--- /dev/null
+++ b/app/src/main/java/fr/gouv/etalab/mastodon/webview/MastalabWebViewClient.java
@@ -0,0 +1,66 @@
+package fr.gouv.etalab.mastodon.webview;
+/* Copyright 2017 Thomas Schneider
+ *
+ * This file is a part of Mastodon Etalab for mastodon.etalab.gouv.fr
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Mastodon Etalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Thomas Schneider; if not,
+ * see . */
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.TextView;
+
+import fr.gouv.etalab.mastodon.helper.Helper;
+import mastodon.etalab.gouv.fr.mastodon.R;
+
+/**
+ * Created by Thomas on 25/06/2017.
+ * Custom WebViewClient
+ */
+
+public class MastalabWebViewClient extends WebViewClient {
+
+ private Activity activity;
+
+ public MastalabWebViewClient(Activity activity){
+ this.activity = activity;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ }
+
+
+ @Override
+ public void onPageStarted (WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
+ LayoutInflater mInflater = LayoutInflater.from(activity);
+ if( actionBar != null){
+ View webview_actionbar = mInflater.inflate(R.layout.webview_actionbar, null);
+ TextView webview_title = (TextView) webview_actionbar.findViewById(R.id.webview_title);
+ webview_title.setText(url);
+ actionBar.setCustomView(webview_actionbar);
+ actionBar.setDisplayShowCustomEnabled(true);
+ }else {
+ activity.setTitle(url);
+ }
+ }
+
+
+}
diff --git a/app/src/main/res/drawable-hdpi/ic_action_download.png b/app/src/main/res/drawable-hdpi/ic_action_download.png
new file mode 100644
index 000000000..f08b33565
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_next_pic.png b/app/src/main/res/drawable-hdpi/ic_next_pic.png
new file mode 100644
index 000000000..652842cd2
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_prev_pic.png b/app/src/main/res/drawable-hdpi/ic_prev_pic.png
new file mode 100644
index 000000000..b84ff3630
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/drawable-ldpi/ic_action_download.png b/app/src/main/res/drawable-ldpi/ic_action_download.png
new file mode 100644
index 000000000..a7d01ca58
Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-ldpi/ic_next_pic.png b/app/src/main/res/drawable-ldpi/ic_next_pic.png
new file mode 100644
index 000000000..c379cb765
Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-ldpi/ic_prev_pic.png b/app/src/main/res/drawable-ldpi/ic_prev_pic.png
new file mode 100644
index 000000000..a622086d7
Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_action_download.png b/app/src/main/res/drawable-mdpi/ic_action_download.png
new file mode 100644
index 000000000..76e1c9b63
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_next_pic.png b/app/src/main/res/drawable-mdpi/ic_next_pic.png
new file mode 100644
index 000000000..194882cfc
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_prev_pic.png b/app/src/main/res/drawable-mdpi/ic_prev_pic.png
new file mode 100644
index 000000000..967f56e74
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_action_download.png b/app/src/main/res/drawable-xhdpi/ic_action_download.png
new file mode 100644
index 000000000..46501ca9b
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_next_pic.png b/app/src/main/res/drawable-xhdpi/ic_next_pic.png
new file mode 100644
index 000000000..5b518ec28
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_prev_pic.png b/app/src/main/res/drawable-xhdpi/ic_prev_pic.png
new file mode 100644
index 000000000..de2df668e
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_download.png b/app/src/main/res/drawable-xxhdpi/ic_action_download.png
new file mode 100644
index 000000000..80a236521
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_next_pic.png b/app/src/main/res/drawable-xxhdpi/ic_next_pic.png
new file mode 100644
index 000000000..3443e3557
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_prev_pic.png b/app/src/main/res/drawable-xxhdpi/ic_prev_pic.png
new file mode 100644
index 000000000..4538ed3b6
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_download.png b/app/src/main/res/drawable-xxxhdpi/ic_action_download.png
new file mode 100644
index 000000000..a017260aa
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_download.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_next_pic.png b/app/src/main/res/drawable-xxxhdpi/ic_next_pic.png
new file mode 100644
index 000000000..2df2d668c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_next_pic.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_prev_pic.png b/app/src/main/res/drawable-xxxhdpi/ic_prev_pic.png
new file mode 100644
index 000000000..1f62de336
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_prev_pic.png differ
diff --git a/app/src/main/res/layout/activity_media.xml b/app/src/main/res/layout/activity_media.xml
new file mode 100644
index 000000000..50b20e375
--- /dev/null
+++ b/app/src/main/res/layout/activity_media.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_webview.xml b/app/src/main/res/layout/activity_webview.xml
index d4053bb14..d3a26a3b4 100644
--- a/app/src/main/res/layout/activity_webview.xml
+++ b/app/src/main/res/layout/activity_webview.xml
@@ -30,7 +30,7 @@
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="10dp"
- android:padding="2dp">
+ android:padding="1dp">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main_media.xml b/app/src/main/res/menu/main_media.xml
new file mode 100644
index 000000000..c2db22f17
--- /dev/null
+++ b/app/src/main/res/menu/main_media.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4f717dc5e..f68e30a08 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -10,7 +10,7 @@
Confidentialité
Cache
Déconnexion
-
+ Télécharger
Connexion
@@ -20,6 +20,8 @@
Annuler
Télécharger
Télécharger %1$s
+ Téléchargement terminé
+ Fichier : %1$s
Mot de passe
Email
Comptes