Merge pull request #791 from nextcloud/implement-incognito-mode

Implement incognito mode
This commit is contained in:
David Luhmer 2019-11-27 21:15:13 +01:00 committed by GitHub
commit 1076a0a522
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 305 additions and 35 deletions

View file

@ -53,16 +53,13 @@ body#darkTheme a:visited {
}
*/
body, blockquote, img, iframe, video, div, table, tbody, tr, td, pre, code, blockquote, p, em, b {
body, blockquote, img, iframe, video, div, table, tbody, tr, td, pre, code, blockquote, p, em, b, span {
width: auto !important;
height: auto !important;
max-width: 100% !important;
}
span {
width: auto !important;
height: auto !important;
max-width: 100% !important;
display: block;
}
@ -102,7 +99,7 @@ a {
#content table {
width:100% !important;
table-layout:fixed;
/* table-layout: fixed; */
}
#header {

View file

@ -21,11 +21,13 @@
package de.luhmer.owncloudnewsreader;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
@ -34,6 +36,8 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ProgressBar;
import androidx.appcompat.widget.Toolbar;
@ -58,13 +62,17 @@ import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm.SORT_DIRECTION;
import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.helper.ThemeUtils;
import de.luhmer.owncloudnewsreader.model.PodcastItem;
import de.luhmer.owncloudnewsreader.model.TTSItem;
import de.luhmer.owncloudnewsreader.widget.WidgetProvider;
public class NewsDetailActivity extends PodcastFragmentActivity {
private static final String TAG = NewsDetailActivity.class.getCanonicalName();
public static final String INCOGNITO_MODE_ENABLED = "INCOGNITO_MODE_ENABLED";
/**
* The {@link PagerAdapter} that will provide
* fragments for each of the sections. We use a
@ -75,7 +83,9 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
protected @BindView(R.id.toolbar) Toolbar toolbar;
// protected @BindView(R.id.bottomAppBar) BottomAppBar bottomAppBar;
protected @BindView(R.id.progressIndicator) ProgressBar progressIndicator;
//protected @BindView(R.id.btn_disable_incognito) ImageButton mBtnDisableIncognito;
/**
* The {@link ViewPager} that will host the section contents.
@ -99,13 +109,59 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
((NewsReaderApplication) getApplication()).getAppComponent().injectActivity(this);
super.onCreate(savedInstanceState);
/*
//make full transparent statusBar
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
*/
/*
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(Color.WHITE);
}
*/
setContentView(R.layout.activity_news_detail);
ButterKnife.bind(this);
/*
// For Debugging the WebView using Chrome Remote Debugging
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
*/
if (toolbar != null) {
ButterKnife.bind(this);
if (toolbar != null) {
setSupportActionBar(toolbar);
}
/*
if (bottomAppBar != null) {
setSupportActionBar(bottomAppBar);
}
*/
//getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
dbConn = new DatabaseConnectionOrm(this);
Intent intent = getIntent();
@ -170,7 +226,38 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
}
mViewPager.addOnPageChangeListener(onPageChangeListener);
}
/*
mBtnDisableIncognito.setOnClickListener(v -> {
toggleIncognitoMode();
});
*/
}
private void toggleIncognitoMode() {
// toggle incognito mode
setIncognitoEnabled(!isIncognitoEnabled());
for(int i = currentPosition-1; i <= currentPosition+1; i++) {
Log.d(TAG, "change incognito for idx: " + i);
WeakReference<NewsDetailFragment> ndf = mSectionsPagerAdapter.items.get(i);
if(ndf != null) {
ndf.get().syncIncognitoState();
ndf.get().startLoadRssItemToWebViewTask();
}
}
}
public static void setWindowFlag(Activity activity, final int bits, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
@Override
protected void onDestroy() {
@ -337,7 +424,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
menuItem_Read = menu.findItem(R.id.action_read);
menuItem_PlayPodcast = menu.findItem(R.id.action_playPodcast);
Set<String> selections = mPrefs.getStringSet("sp_news_detail_actionbar_icons", new HashSet<String>());
Set<String> selections = mPrefs.getStringSet("sp_news_detail_actionbar_icons", new HashSet<>());
String[] selected = selections.toArray(new String[] {});
for(String selection : selected) {
switch(selection) {
@ -358,6 +445,8 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
updateActionBarIcons();
initIncognitoMode();
return true;
}
@ -469,6 +558,10 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
startActivity(Intent.createChooser(share, "Share Item"));
break;
case R.id.action_incognito_mode:
toggleIncognitoMode();
break;
}
@ -510,6 +603,65 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
super.finish();
}
public boolean isIncognitoEnabled() {
return mPrefs.getBoolean(INCOGNITO_MODE_ENABLED, false);
}
public void setIncognitoEnabled(boolean enabled) {
mPrefs.edit().putBoolean(INCOGNITO_MODE_ENABLED, enabled).commit();
initIncognitoMode();
}
public void initIncognitoMode() {
int color = getResources().getColor(isIncognitoEnabled() ? R.color.material_grey_900 : R.color.colorPrimary);
ThemeUtils.colorizeToolbar(toolbar, color);
//ThemeUtils.colorizeToolbar(bottomAppBar, color);
//ThemeUtils.changeStatusBarColor(this, color);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//getWindow().setNavigationBarColor(color);
getWindow().setStatusBarColor(color);
/*
switch (ThemeChooser.getSelectedTheme()) {
case LIGHT:
Log.d(TAG, "initIncognitoMode: LIGHT");
setLightStatusBar(getWindow().getDecorView());
getWindow().setStatusBarColor(Color.WHITE);
break;
case DARK:
clearLightStatusBar(getWindow().getDecorView());
Log.d(TAG, "initIncognitoMode: DARK");
getWindow().setStatusBarColor(getResources().getColor(R.color.material_grey_900));
break;
case OLED:
clearLightStatusBar(getWindow().getDecorView());
Log.d(TAG, "initIncognitoMode: OLED");
getWindow().setStatusBarColor(Color.BLACK);
break;
}
*/
}
}
/*
private void setLightStatusBar(@NonNull View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility(); // get current flag
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // add LIGHT_STATUS_BAR to flag
view.setSystemUiVisibility(flags);
}
}
public static void clearLightStatusBar(@NonNull View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
}
}
*/
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.

View file

@ -180,13 +180,24 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
} else {
mWebView.restoreState(savedInstanceState);
mProgressBarLoading.setVisibility(View.GONE);
// Make sure to sync the incognitio on retained views
syncIncognitoState();
}
setUpGestureDetector();
return rootView;
}
protected void syncIncognitoState() {
NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity());
boolean isIncognito = ndActivity.isIncognitoEnabled();
mWebView.getSettings().setBlockNetworkLoads(isIncognito);
mWebView.getSettings().setBlockNetworkImage(isIncognito);
}
@Override
public void onSaveInstanceState(Bundle outState) {
mWebView.saveState(outState);
@ -224,7 +235,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
});
}
private void startLoadRssItemToWebViewTask() {
protected void startLoadRssItemToWebViewTask() {
Log.d(TAG, "startLoadRssItemToWebViewTask() called");
mWebView.setVisibility(View.GONE);
mProgressBarLoading.setVisibility(View.VISIBLE);
@ -285,16 +296,18 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
WebSettings webSettings = mWebView.getSettings();
//webSettings.setPluginState(WebSettings.PluginState.ON);
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setDomStorageEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(false);
webSettings.setSupportMultipleWindows(false);
webSettings.setSupportZoom(false);
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setDomStorageEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(false);
webSettings.setSupportMultipleWindows(false);
webSettings.setSupportZoom(false);
webSettings.setAppCacheEnabled(true);
webSettings.setMediaPlaybackRequiresUserGesture(true);
syncIncognitoState();
registerForContextMenu(mWebView);
mWebView.setWebChromeClient(new ProgressBarWebChromeClient(mProgressbarWebView));
@ -305,6 +318,8 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
//Log.d(TAG, "shouldInterceptRequest: " + url);
boolean isAd;
if (!loadedUrls.containsKey(url)) {
isAd = AdBlocker.isAd(url);
@ -394,7 +409,7 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
String imgaltval;
String imgsrcval;
imgsrcval = imageUrl.substring(imageUrl.lastIndexOf('/') + 1, imageUrl.length());
imgsrcval = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
Elements imgtag = htmlDoc.getElementsByAttributeValueContaining("src", imageUrl);
try {

View file

@ -49,7 +49,7 @@ public class PiPVideoPlaybackActivity extends AppCompatActivity {
setContentView(R.layout.activity_pip_video_playback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
//moveTaskToBack(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PictureInPictureParams.Builder pictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
@ -59,9 +59,6 @@ public class PiPVideoPlaybackActivity extends AppCompatActivity {
} else {
enterPictureInPictureMode();
}
enterPictureInPictureMode();
} else {
Toast.makeText(this, "This device does not support video playback.", Toast.LENGTH_LONG).show();
finish();

View file

@ -78,7 +78,9 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
super.onCreate(savedInstanceState);
ThemeChooser.afterOnCreate(this);
if (mApi.getAPI() instanceof Proxy) { // Single Sign On
//if (mApi.getAPI() instanceof Proxy) { // doesn't work.. retrofit is also a "proxy"
boolean useSSO = mPrefs.getBoolean(SettingsActivity.SW_USE_SINGLE_SIGN_ON, false);
if(useSSO) {
VersionCheckHelper.verifyMinVersion(this, MIN_NEXTCLOUD_FILES_APP_VERSION_CODE);
}

View file

@ -24,6 +24,7 @@ import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.helper.ImageHandler;
import de.luhmer.owncloudnewsreader.helper.ThemeChooser;
import static de.luhmer.owncloudnewsreader.NewsDetailActivity.INCOGNITO_MODE_ENABLED;
import static de.luhmer.owncloudnewsreader.helper.ThemeChooser.THEME;
@ -84,6 +85,8 @@ public class RssItemToHtmlTask extends AsyncTask<Void, Void, String> {
* @return given RSS item as full HTML page
*/
public static String getHtmlPage(RssItem rssItem, boolean showHeader, SharedPreferences mPrefs, boolean isRightToLeft) {
boolean incognitoMode = mPrefs.getBoolean(INCOGNITO_MODE_ENABLED, false);
String favIconUrl = null;
Feed feed = rssItem.getFeed();
@ -122,7 +125,14 @@ public class RssItemToHtmlTask extends AsyncTask<Void, Void, String> {
}
String description = rssItem.getBody();
description = getDescriptionWithCachedImages(description).trim();
if(!incognitoMode) {
// If incognito mode is disabled, try getting images from cache
description = getDescriptionWithCachedImages(description).trim();
} else {
// When incognito is on, we need to provide some error handling
//description = description.replaceAll("<img", "<img onerror=\"this.style='width: 40px !important; height: 40px !important'\" ");
description = description.replaceAll("<img", "<img width=\"40px\" height=\"40px\" ");
}
description = replacePatternInText(PATTERN_PRELOAD_VIDEOS_REMOVE, description, "$1 $3"); // remove whatever preload is there
description = replacePatternInText(PATTERN_PRELOAD_VIDEOS_INSERT, description, "$1 preload=\"metadata\" $3"); // add preload attribute
description = replacePatternInText(PATTERN_AUTOPLAY_VIDEOS_1, description, "$1 $3");

View file

@ -1,15 +1,44 @@
/**
* Android ownCloud News
*
* @author David Luhmer
* @copyright 2019 David Luhmer david-dev@live.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.luhmer.owncloudnewsreader.helper;
import android.app.Activity;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.SearchView;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.appcompat.widget.ActionMenuView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import java.lang.reflect.Field;
import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;
import de.luhmer.owncloudnewsreader.R;
public class ThemeUtils {
@ -67,4 +96,42 @@ public class ThemeUtils {
}
}
/**
* Use this method to colorize the toolbar to the desired target color
* @param toolbarView toolbar view being colored
* @param toolbarBackgroundColor the target background color
*/
public static void colorizeToolbar(Toolbar toolbarView, @ColorInt int toolbarBackgroundColor) {
toolbarView.setBackgroundColor(toolbarBackgroundColor);
for(int i = 0; i < toolbarView.getChildCount(); i++) {
final View v = toolbarView.getChildAt(i);
v.setBackgroundColor(toolbarBackgroundColor);
if(v instanceof ActionMenuView) {
for(int j = 0; j < ((ActionMenuView)v).getChildCount(); j++) {
v.setBackgroundColor(toolbarBackgroundColor);
}
}
}
}
/**
* Use this method to colorize the status bar to the desired target color
* @param activity
* @param statusBarColor
*/
public static void changeStatusBarColor(Activity activity, @ColorInt int statusBarColor) {
Window window = activity.getWindow();
// clear FLAG_TRANSLUCENT_STATUS flag:
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(statusBarColor);
}
}
}

View file

@ -0,0 +1,8 @@
<!-- drawable/incognito.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M12,3C9.31,3 7.41,4.22 7.41,4.22L6,9H18L16.59,4.22C16.59,4.22 14.69,3 12,3M12,11C9.27,11 5.39,11.54 5.13,11.59C4.09,11.87 3.25,12.15 2.59,12.41C1.58,12.75 1,13 1,13H23C23,13 22.42,12.75 21.41,12.41C20.75,12.15 19.89,11.87 18.84,11.59C18.84,11.59 14.82,11 12,11M7.5,14A3.5,3.5 0 0,0 4,17.5A3.5,3.5 0 0,0 7.5,21A3.5,3.5 0 0,0 11,17.5C11,17.34 11,17.18 10.97,17.03C11.29,16.96 11.63,16.9 12,16.91C12.37,16.91 12.71,16.96 13.03,17.03C13,17.18 13,17.34 13,17.5A3.5,3.5 0 0,0 16.5,21A3.5,3.5 0 0,0 20,17.5A3.5,3.5 0 0,0 16.5,14C15.03,14 13.77,14.9 13.25,16.19C12.93,16.09 12.55,16 12,16C11.45,16 11.07,16.09 10.75,16.19C10.23,14.9 8.97,14 7.5,14M7.5,15A2.5,2.5 0 0,1 10,17.5A2.5,2.5 0 0,1 7.5,20A2.5,2.5 0 0,1 5,17.5A2.5,2.5 0 0,1 7.5,15M16.5,15A2.5,2.5 0 0,1 19,17.5A2.5,2.5 0 0,1 16.5,20A2.5,2.5 0 0,1 14,17.5A2.5,2.5 0 0,1 16.5,15Z" />
</vector>

View file

@ -1,8 +1,8 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent">
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- SlidingUpPanelLayout doesn't work with layout_behavior, use marginTop -->
<de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout
@ -17,6 +17,11 @@
sothree:umanoParallaxOffset="100dp"
sothree:umanoDragView="@+id/name">
<!--
for bottom toolbar, replace marginTop above with marginBottom
android:layout_marginBottom="?attr/actionBarSize"
-->
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
@ -48,10 +53,6 @@
</de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout>
<include
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_layout" />
<de.luhmer.owncloudnewsreader.view.AnimatingProgressBar
android:id="@+id/progressIndicator"
android:layout_width="match_parent"
@ -61,4 +62,20 @@
android:layoutDirection="ltr"
style="?android:attr/progressBarStyleHorizontal" />
<!--
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:theme="@style/ToolbarTheme"
app:popupTheme="@style/ToolbarOptionMenuBackgroundTheme">
</com.google.android.material.bottomappbar.BottomAppBar>
-->
<include
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_layout" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,10 +1,10 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NewsDetailFragment" >
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
@ -42,5 +42,4 @@
android:background="@color/material_red_600"
android:visibility="gone" />
</RelativeLayout>

View file

@ -53,4 +53,10 @@
android:icon="@drawable/ic_action_share"
android:title="@string/action_Share" />
<item
android:id="@+id/action_incognito_mode"
app:showAsAction="ifRoom"
android:icon="@drawable/incognito"
android:title="Incognito Mode"/>
</menu>