implement chrome custom tabs

This commit is contained in:
Andrew Dolgov 2015-11-28 16:30:12 +03:00
parent b28fef66e8
commit 4b09961a30
15 changed files with 199 additions and 43 deletions

View File

@ -6,7 +6,7 @@ android {
defaultConfig { defaultConfig {
applicationId "org.fox.ttrss" applicationId "org.fox.ttrss"
minSdkVersion 15 minSdkVersion 16
targetSdkVersion 23 targetSdkVersion 23
} }
@ -39,6 +39,7 @@ dependencies {
compile 'me.relex:circleindicator:1.1.1@aar' compile 'me.relex:circleindicator:1.1.1@aar'
compile 'com.viewpagerindicator:library:2.4.1' compile 'com.viewpagerindicator:library:2.4.1'
compile 'com.nhaarman.listviewanimations:lib-core:3.1.0@aar' compile 'com.nhaarman.listviewanimations:lib-core:3.1.0@aar'
compile 'com.android.support:customtabs:23.0.0'
compile files('libs/nineoldandroids-2.4.0.jar') compile files('libs/nineoldandroids-2.4.0.jar')
compile files('libs/YouTubeAndroidPlayerApi.jar') compile files('libs/YouTubeAndroidPlayerApi.jar')
} }

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fox.ttrss" package="org.fox.ttrss"
android:versionCode="381" android:versionCode="382"
android:versionName="1.153" > android:versionName="1.154" >
<uses-sdk <uses-sdk
android:minSdkVersion="15" android:minSdkVersion="16"
android:targetSdkVersion="23" /> android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />

View File

@ -226,8 +226,9 @@ public class ArticleFragment extends Fragment {
URL url = new URL(m_article.link.trim()); URL url = new URL(m_article.link.trim());
String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(),
url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString(); url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent); m_activity.openUri(Uri.parse(uri));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
m_activity.toast(R.string.error_other_error); m_activity.toast(R.string.error_other_error);
@ -264,8 +265,8 @@ public class ArticleFragment extends Fragment {
URL url = new URL(m_article.link.trim()); URL url = new URL(m_article.link.trim());
String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(),
url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString(); url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent); m_activity.openUri(Uri.parse(uri));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
m_activity.toast(R.string.error_other_error); m_activity.toast(R.string.error_other_error);
@ -304,9 +305,8 @@ public class ArticleFragment extends Fragment {
m_article.comments_link : m_article.link); m_article.comments_link : m_article.link);
String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(),
url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString(); url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString();
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(uri)); m_activity.openUri(Uri.parse(uri));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
m_activity.toast(R.string.error_other_error); m_activity.toast(R.string.error_other_error);
@ -389,8 +389,7 @@ public class ArticleFragment extends Fragment {
@Override @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { public boolean shouldOverrideUrlLoading(WebView view, String url) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); m_activity.openUri(Uri.parse(url));
startActivity(intent);
return true; return true;

View File

@ -387,9 +387,7 @@ public class ArticleImagesPagerActivity extends CommonActivity implements Gestur
case R.id.article_img_open: case R.id.article_img_open:
if (url != null) { if (url != null) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, openUri(Uri.parse(url));
Uri.parse(url));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
toast(R.string.error_other_error); toast(R.string.error_other_error);

View File

@ -2,13 +2,23 @@ package org.fox.ttrss;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.customtabs.CustomTabsCallback;
import android.support.customtabs.CustomTabsClient;
import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.CustomTabsServiceConnection;
import android.support.customtabs.CustomTabsSession;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.util.TypedValue;
import android.view.Display; import android.view.Display;
import android.widget.Toast; import android.widget.Toast;
@ -42,6 +52,21 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
private String m_theme; private String m_theme;
private boolean m_needRestart; private boolean m_needRestart;
protected CustomTabsClient m_customTabClient;
protected CustomTabsServiceConnection m_customTabServiceConnection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) {
m_customTabClient = customTabsClient;
m_customTabClient.warmup(0);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
m_customTabClient = null;
}
};
protected SharedPreferences m_prefs; protected SharedPreferences m_prefs;
protected void setSmallScreen(boolean smallScreen) { protected void setSmallScreen(boolean smallScreen) {
@ -96,6 +121,11 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
@Override @Override
public void onDestroy() { public void onDestroy() {
if (m_customTabServiceConnection != null) {
unbindService(m_customTabServiceConnection);
}
super.onDestroy(); super.onDestroy();
} }
@ -114,6 +144,8 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
m_theme = m_prefs.getString("theme", CommonActivity.THEME_DEFAULT); m_theme = m_prefs.getString("theme", CommonActivity.THEME_DEFAULT);
} }
CustomTabsClient.bindCustomTabsService(this, "com.android.chrome", m_customTabServiceConnection);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }
@ -172,5 +204,48 @@ public class CommonActivity extends ActionBarActivity implements SharedPreferenc
m_needRestart = Arrays.asList(filter).indexOf(key) != -1; m_needRestart = Arrays.asList(filter).indexOf(key) != -1;
} }
private CustomTabsSession getCustomTabSession() {
return m_customTabClient.newSession(new CustomTabsCallback() {
@Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {
super.onNavigationEvent(navigationEvent, extras);
}
});
}
// uses chrome custom tabs when available
public void openUri(Uri uri) {
if (m_customTabClient != null) {
TypedValue tvBackground = new TypedValue();
getTheme().resolveAttribute(R.attr.colorPrimary, tvBackground, true);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getCustomTabSession());
builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);
builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
builder.setToolbarColor(tvBackground.data);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, uri.toString());
shareIntent.putExtra(Intent.EXTRA_TEXT, uri.toString());
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, shareIntent, 0);
builder.setActionButton(BitmapFactory.decodeResource(getResources(), R.drawable.ic_share),
getString(R.string.share_article), pendingIntent);
CustomTabsIntent intent = builder.build();
intent.launchUrl(this, uri);
} else {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
} }

View File

@ -185,8 +185,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
Article article = getArticleAtPosition(info.position); Article article = getArticleAtPosition(info.position);
if (article != null) { if (article != null) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(article.link)); m_activity.openUri(Uri.parse(article.link));
startActivity(browserIntent);
if (article.unread) { if (article.unread) {
article.unread = false; article.unread = false;
@ -1255,9 +1254,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
startActivity(intent); startActivity(intent);
} else { } else {
Intent intent = new Intent(Intent.ACTION_VIEW, m_activity.openUri(Uri.parse(article.flavorStreamUri));
Uri.parse(article.flavorStreamUri));
startActivity(intent);
} }
} else if ("video".equals(article.flavorImage.tagName().toLowerCase())) { } else if ("video".equals(article.flavorImage.tagName().toLowerCase())) {

View File

@ -532,9 +532,7 @@ public class OnlineActivity extends CommonActivity {
case R.id.article_img_open: case R.id.article_img_open:
if (getLastContentImageHitTestUrl() != null) { if (getLastContentImageHitTestUrl() != null) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, openUri(Uri.parse(getLastContentImageHitTestUrl()));
Uri.parse(getLastContentImageHitTestUrl()));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
toast(R.string.error_other_error); toast(R.string.error_other_error);
@ -658,8 +656,7 @@ public class OnlineActivity extends CommonActivity {
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition(); int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse((String)itemUrls[selectedPosition])); openUri(Uri.parse((String)itemUrls[selectedPosition]));
startActivity(browserIntent);
dialog.cancel(); dialog.cancel();
} }

View File

@ -229,9 +229,7 @@ public class VideoPlayerActivity extends CommonActivity {
case R.id.article_vid_open: case R.id.article_vid_open:
if (m_streamUri != null) { if (m_streamUri != null) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, openUri(Uri.parse(m_streamUri));
Uri.parse(m_streamUri));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
toast(R.string.error_other_error); toast(R.string.error_other_error);

View File

@ -103,9 +103,7 @@ public class YoutubePlayerActivity extends CommonActivity implements YouTubePlay
case R.id.article_vid_open: case R.id.article_vid_open:
if (m_streamUri != null) { if (m_streamUri != null) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, openUri(Uri.parse(m_streamUri));
Uri.parse(m_streamUri));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
toast(R.string.error_other_error); toast(R.string.error_other_error);

View File

@ -83,9 +83,7 @@ public class OfflineActivity extends CommonActivity {
case R.id.article_img_open: case R.id.article_img_open:
if (getLastContentImageHitTestUrl() != null) { if (getLastContentImageHitTestUrl() != null) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, openUri(Uri.parse(getLastContentImageHitTestUrl()));
Uri.parse(getLastContentImageHitTestUrl()));
startActivity(intent);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
toast(R.string.error_other_error); toast(R.string.error_other_error);

View File

@ -168,8 +168,8 @@ public class OfflineArticleFragment extends Fragment {
URL url = new URL(link.trim()); URL url = new URL(link.trim());
String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(),
url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString(); url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent); m_activity.openUri(Uri.parse(uri));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
m_activity.toast(R.string.error_other_error); m_activity.toast(R.string.error_other_error);
@ -206,8 +206,8 @@ public class OfflineArticleFragment extends Fragment {
URL url = new URL(link.trim()); URL url = new URL(link.trim());
String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), String uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(),
url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString(); url.getPort(), url.getPath(), url.getQuery(), url.getRef()).toString();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent); m_activity.openUri(Uri.parse(uri));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
m_activity.toast(R.string.error_other_error); m_activity.toast(R.string.error_other_error);
@ -250,8 +250,7 @@ public class OfflineArticleFragment extends Fragment {
@Override @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { public boolean shouldOverrideUrlLoading(WebView view, String url) {
try { try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); m_activity.openUri(Uri.parse(url));
startActivity(intent);
return true; return true;

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/res/anim/slide_in_left.xml
**
** Copyright 2007, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-50%p" android:toXDelta="0" android:duration="200"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
</set>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/res/anim/slide_in_right.xml
**
** Copyright 2007, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="50%p" android:toXDelta="0" android:duration="200"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
</set>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/res/anim/slide_out_left.xml
**
** Copyright 2007, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-50%p" android:duration="200"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
</set>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/res/anim/slide_out_right.xml
**
** Copyright 2007, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="50%p" android:duration="200"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
</set>