Make custom tabs follow app theme

This commit is contained in:
NekoInverter 2021-01-07 15:25:06 +08:00 committed by 世界
parent 2699e46c96
commit b1770331f8
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
16 changed files with 25 additions and 2509 deletions

View File

@ -51,6 +51,7 @@ repositories {
dependencies {
implementation "androidx.browser:browser:1.3.0"
implementation 'androidx.core:core-ktx:1.5.0-alpha05'
implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
@ -341,8 +342,8 @@ android {
if (set.name.matches("(mini|full).*")) {
if (set.name.contains("Apple")) {
set.assets.srcDirs = ["src/main/assets", "src/emojis/apple"]
/*} else if (set.name.contains("Twitter")) {
set.assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]*/
/*} else if (set.name.contains("Twitter")) {
set.assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]*/
} else {
set.assets.srcDirs = ["src/main/assets", "src/emojis/twitter"]
}

View File

@ -19,6 +19,13 @@ import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsServiceConnection;
import androidx.browser.customtabs.CustomTabsSession;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.BuildVars;
@ -30,11 +37,6 @@ import org.telegram.messenger.R;
import org.telegram.messenger.ShareBroadcastReceiver;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.support.customtabs.CustomTabsCallback;
import org.telegram.messenger.support.customtabs.CustomTabsClient;
import org.telegram.messenger.support.customtabs.CustomTabsIntent;
import org.telegram.messenger.support.customtabs.CustomTabsServiceConnection;
import org.telegram.messenger.support.customtabs.CustomTabsSession;
import org.telegram.messenger.support.customtabsclient.shared.CustomTabsHelper;
import org.telegram.messenger.support.customtabsclient.shared.ServiceConnection;
import org.telegram.messenger.support.customtabsclient.shared.ServiceConnectionCallback;
@ -295,11 +297,21 @@ public class Browser {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getSession());
builder.addMenuItem(LocaleController.getString("CopyLink", R.string.CopyLink), copy);
builder.setToolbarColor(Theme.getColor(Theme.key_actionBarBrowser));
boolean dark = false;
if (Theme.getActiveTheme().isDark()) {
dark = true;
} else if (AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_windowBackgroundWhite)) < 0.721f) {
dark = true;
}
builder.setColorScheme(dark ? CustomTabsIntent.COLOR_SCHEME_DARK : CustomTabsIntent.COLOR_SCHEME_LIGHT);
CustomTabColorSchemeParams params = new CustomTabColorSchemeParams.Builder()
.setToolbarColor(Theme.getColor(Theme.key_actionBarBrowser))
.build();
builder.setDefaultColorSchemeParams(params);
builder.setShowTitle(true);
builder.setActionButton(BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha), LocaleController.getString("ShareFile", R.string.ShareFile), PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, share, 0), true);
CustomTabsIntent intent = builder.build();
intent.setUseNewTask();
intent.intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.launchUrl(context, uri);
return;
}

View File

@ -1,100 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.os.Bundle;
/**
* A callback class for custom tabs client to get messages regarding events in their custom tabs.
*/
public class CustomTabsCallback {
/**
* Sent when the tab has started loading a page.
*/
public static final int NAVIGATION_STARTED = 1;
/**
* Sent when the tab has finished loading a page.
*/
public static final int NAVIGATION_FINISHED = 2;
/**
* Sent when the tab couldn't finish loading due to a failure.
*/
public static final int NAVIGATION_FAILED = 3;
/**
* Sent when loading was aborted by a user action before it finishes like clicking on a link
* or refreshing the page.
*/
public static final int NAVIGATION_ABORTED = 4;
/**
* Sent when the tab becomes visible.
*/
public static final int TAB_SHOWN = 5;
/**
* Sent when the tab becomes hidden.
*/
public static final int TAB_HIDDEN = 6;
/**
* To be called when a navigation event happens.
*
* @param navigationEvent The code corresponding to the navigation event.
* @param extras Reserved for future use.
*/
public void onNavigationEvent(int navigationEvent, Bundle extras) {}
/**
* Unsupported callbacks that may be provided by the implementation.
*
* <p>
* <strong>Note:</strong>Clients should <strong>never</strong> rely on this callback to be
* called and/or to have a defined behavior, as it is entirely implementation-defined and not
* supported.
*
* <p> This can be used by implementations to add extra callbacks, for testing or experimental
* purposes.
*
* @param callbackName Name of the extra callback.
* @param args Arguments for the calback
*/
public void extraCallback(String callbackName, Bundle args) {}
/**
* Called when {@link CustomTabsSession} has requested a postMessage channel through
* {@link CustomTabsService#requestPostMessageChannel(
* CustomTabsSessionToken, android.net.Uri)} and the channel
* is ready for sending and receiving messages on both ends.
*
* @param extras Reserved for future use.
*/
public void onMessageChannelReady(Bundle extras) {}
/**
* Called when a tab controlled by this {@link CustomTabsSession} has sent a postMessage.
* If postMessage() is called from a single thread, then the messages will be posted in the
* same order. When received on the client side, it is the client's responsibility to preserve
* the ordering further.
*
* @param message The message sent.
* @param extras Reserved for future use.
*/
public void onPostMessage(String message, Bundle extras) {}
}

View File

@ -1,245 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
public class CustomTabsClient {
private final ICustomTabsService mService;
private final ComponentName mServiceComponentName;
CustomTabsClient(ICustomTabsService service, ComponentName componentName) {
mService = service;
mServiceComponentName = componentName;
}
/**
* Bind to a {@link CustomTabsService} using the given package name and
* {@link ServiceConnection}.
* @param context {@link Context} to use while calling
* {@link Context#bindService(Intent, ServiceConnection, int)}
* @param packageName Package name to set on the {@link Intent} for binding.
* @param connection {@link CustomTabsServiceConnection} to use when binding. This will
* return a {@link CustomTabsClient} on
* {@link CustomTabsServiceConnection
* #onCustomTabsServiceConnected(ComponentName, CustomTabsClient)}
* @return Whether the binding was successful.
*/
public static boolean bindCustomTabsService(Context context,
String packageName, CustomTabsServiceConnection connection) {
Intent intent = new Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
if (!TextUtils.isEmpty(packageName)) intent.setPackage(packageName);
return context.bindService(intent, connection,
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY);
}
/**
* Returns the preferred package to use for Custom Tabs, preferring the default VIEW handler.
*
* @see #getPackageName(Context, List<String>, boolean)
*/
public static String getPackageName(Context context, @Nullable List<String> packages) {
return getPackageName(context, packages, false);
}
/**
* Returns the preferred package to use for Custom Tabs.
*
* The preferred package name is the default VIEW intent handler as long as it supports Custom
* Tabs. To modify this preferred behavior, set <code>ignoreDefault</code> to true and give a
* non empty list of package names in <code>packages</code>.
*
* @param context {@link Context} to use for querying the packages.
* @param packages Ordered list of packages to test for Custom Tabs support, in
* decreasing order of priority.
* @param ignoreDefault If set, the default VIEW handler won't get priority over other browsers.
* @return The preferred package name for handling Custom Tabs, or <code>null</code>.
*/
public static String getPackageName(
Context context, @Nullable List<String> packages, boolean ignoreDefault) {
PackageManager pm = context.getPackageManager();
List<String> packageNames = packages == null ? new ArrayList<String>() : packages;
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
if (!ignoreDefault) {
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
if (defaultViewHandlerInfo != null) {
String packageName = defaultViewHandlerInfo.activityInfo.packageName;
packageNames = new ArrayList<>(packageNames.size() + 1);
packageNames.add(packageName);
if (packages != null) packageNames.addAll(packages);
}
}
Intent serviceIntent = new Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
for (String packageName : packageNames) {
serviceIntent.setPackage(packageName);
if (pm.resolveService(serviceIntent, 0) != null) return packageName;
}
return null;
}
/**
* Connects to the Custom Tabs warmup service, and initializes the browser.
*
* This convenience method connects to the service, and immediately warms up the Custom Tabs
* implementation. Since service connection is asynchronous, the return code is not the return
* code of warmup.
* This call is optional, and clients are encouraged to connect to the service, call
* <code>warmup()</code> and create a session. In this case, calling this method is not
* necessary.
*
* @param context {@link Context} to use to connect to the remote service.
* @param packageName Package name of the target implementation.
* @return Whether the binding was successful.
*/
public static boolean connectAndInitialize(Context context, String packageName) {
if (packageName == null) return false;
final Context applicationContext = context.getApplicationContext();
CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
@Override
public final void onCustomTabsServiceConnected(
ComponentName name, CustomTabsClient client) {
client.warmup(0);
// Unbinding immediately makes the target process "Empty", provided that it is
// not used by anyone else, and doesn't contain any Activity. This makes it
// likely to get killed, but is preferable to keeping the connection around.
applicationContext.unbindService(this);
}
@Override
public final void onServiceDisconnected(ComponentName componentName) { }
};
try {
return bindCustomTabsService(applicationContext, packageName, connection);
} catch (SecurityException e) {
return false;
}
}
/**
* Warm up the browser process.
*
* Allows the browser application to pre-initialize itself in the background. Significantly
* speeds up URL opening in the browser. This is asynchronous and can be called several times.
*
* @param flags Reserved for future use.
* @return Whether the warmup was successful.
*/
public boolean warmup(long flags) {
try {
return mService.warmup(flags);
} catch (RemoteException e) {
return false;
}
}
/**
* Creates a new session through an ICustomTabsService with the optional callback. This session
* can be used to associate any related communication through the service with an intent and
* then later with a Custom Tab. The client can then send later service calls or intents to
* through same session-intent-Custom Tab association.
* @param callback The callback through which the client will receive updates about the created
* session. Can be null. All the callbacks will be received on the UI thread.
* @return The session object that was created as a result of the transaction. The client can
* use this to relay session specific calls.
* Null on error.
*/
public CustomTabsSession newSession(final CustomTabsCallback callback) {
ICustomTabsCallback.Stub wrapper = new ICustomTabsCallback.Stub() {
private Handler mHandler = new Handler(Looper.getMainLooper());
@Override
public void onNavigationEvent(final int navigationEvent, final Bundle extras) {
if (callback == null) return;
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onNavigationEvent(navigationEvent, extras);
}
});
}
@Override
public void extraCallback(final String callbackName, final Bundle args)
throws RemoteException {
if (callback == null) return;
mHandler.post(new Runnable() {
@Override
public void run() {
callback.extraCallback(callbackName, args);
}
});
}
@Override
public void onMessageChannelReady(final Bundle extras)
throws RemoteException {
if (callback == null) return;
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onMessageChannelReady(extras);
}
});
}
@Override
public void onPostMessage(final String message, final Bundle extras)
throws RemoteException {
if (callback == null) return;
mHandler.post(new Runnable() {
@Override
public void run() {
callback.onPostMessage(message, extras);
}
});
}
};
try {
if (!mService.newSession(wrapper)) return null;
} catch (RemoteException e) {
return null;
}
return new CustomTabsSession(mService, wrapper, mServiceComponentName);
}
public Bundle extraCommand(String commandName, Bundle args) {
try {
return mService.extraCommand(commandName, args);
} catch (RemoteException e) {
return null;
}
}
}

View File

@ -1,566 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.AnimRes;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.app.BundleCompat;
import androidx.core.content.ContextCompat;
import android.view.View;
import android.widget.RemoteViews;
import java.util.ArrayList;
/**
* Class holding the {@link Intent} and start bundle for a Custom Tabs Activity.
*
* <p>
* <strong>Note:</strong> The constants below are public for the browser implementation's benefit.
* You are strongly encouraged to use {@link CustomTabsIntent.Builder}.</p>
*/
public final class CustomTabsIntent {
/**
* Indicates that the user explicitly opted out of Custom Tabs in the calling application.
* <p>
* If an application provides a mechanism for users to opt out of Custom Tabs, this extra should
* be provided with {@link Intent#FLAG_ACTIVITY_NEW_TASK} to ensure the browser does not attempt
* to trigger any Custom Tab-like experiences as a result of the VIEW intent.
* <p>
* If this extra is present with {@link Intent#FLAG_ACTIVITY_NEW_TASK}, all Custom Tabs
* customizations will be ignored.
*/
private static final String EXTRA_USER_OPT_OUT_FROM_CUSTOM_TABS =
"android.support.customtabs.extra.user_opt_out";
/**
* Extra used to match the session. This has to be included in the intent to open in
* a custom tab. This is the same IBinder that gets passed to ICustomTabsService#newSession.
* Null if there is no need to match any service side sessions with the intent.
*/
public static final String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
/**
* Extra that changes the background color for the toolbar. colorRes is an int that specifies a
* {@link Color}, not a resource id.
*/
public static final String EXTRA_TOOLBAR_COLOR =
"android.support.customtabs.extra.TOOLBAR_COLOR";
/**
* Boolean extra that enables the url bar to hide as the user scrolls down the page
*/
public static final String EXTRA_ENABLE_URLBAR_HIDING =
"android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
/**
* Extra bitmap that specifies the icon of the back button on the toolbar. If the client chooses
* not to customize it, a default close button will be used.
*/
public static final String EXTRA_CLOSE_BUTTON_ICON =
"android.support.customtabs.extra.CLOSE_BUTTON_ICON";
/**
* Extra (int) that specifies state for showing the page title. Default is {@link #NO_TITLE}.
*/
public static final String EXTRA_TITLE_VISIBILITY_STATE =
"android.support.customtabs.extra.TITLE_VISIBILITY";
/**
* Don't show any title. Shows only the domain.
*/
public static final int NO_TITLE = 0;
/**
* Shows the page title and the domain.
*/
public static final int SHOW_PAGE_TITLE = 1;
/**
* Bundle used for adding a custom action button to the custom tab toolbar. The client should
* provide a description, an icon {@link Bitmap} and a {@link PendingIntent} for the button.
* All three keys must be present.
*/
public static final String EXTRA_ACTION_BUTTON_BUNDLE =
"android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
/**
* List<Bundle> used for adding items to the top and bottom toolbars. The client should
* provide an ID, a description, an icon {@link Bitmap} for each item. They may also provide a
* {@link PendingIntent} if the item is a button.
*/
public static final String EXTRA_TOOLBAR_ITEMS =
"android.support.customtabs.extra.TOOLBAR_ITEMS";
/**
* Extra that changes the background color for the secondary toolbar. The value should be an
* int that specifies a {@link Color}, not a resource id.
*/
public static final String EXTRA_SECONDARY_TOOLBAR_COLOR =
"android.support.customtabs.extra.SECONDARY_TOOLBAR_COLOR";
/**
* Key that specifies the {@link Bitmap} to be used as the image source for the action button.
* The icon should't be more than 24dp in height (No padding needed. The button itself will be
* 48dp in height) and have a width/height ratio of less than 2.
*/
public static final String KEY_ICON = "android.support.customtabs.customaction.ICON";
/**
* Key that specifies the content description for the custom action button.
*/
public static final String KEY_DESCRIPTION =
"android.support.customtabs.customaction.DESCRIPTION";
/**
* Key that specifies the PendingIntent to launch when the action button or menu item was
* clicked. The custom tab will be calling {@link PendingIntent#send()} on clicks after adding
* the url as data. The client app can call {@link Intent#getDataString()} to get the url.
*/
public static final String KEY_PENDING_INTENT =
"android.support.customtabs.customaction.PENDING_INTENT";
/**
* Extra boolean that specifies whether the custom action button should be tinted. Default is
* false and the action button will not be tinted.
*/
public static final String EXTRA_TINT_ACTION_BUTTON =
"android.support.customtabs.extra.TINT_ACTION_BUTTON";
/**
* Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a
* separate {@link Bundle} for each custom menu item.
*/
public static final String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
/**
* Key for specifying the title of a menu item.
*/
public static final String KEY_MENU_ITEM_TITLE =
"android.support.customtabs.customaction.MENU_ITEM_TITLE";
/**
* Bundle constructed out of {@link ActivityOptionsCompat} that will be running when the
* {@link Activity} that holds the custom tab gets finished. A similar ActivityOptions
* for creation should be constructed and given to the startActivity() call that
* launches the custom tab.
*/
public static final String EXTRA_EXIT_ANIMATION_BUNDLE =
"android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
/**
* Boolean extra that specifies whether a default share button will be shown in the menu.
*/
public static final String EXTRA_DEFAULT_SHARE_MENU_ITEM =
"android.support.customtabs.extra.SHARE_MENU_ITEM";
/**
* Extra that specifies the {@link RemoteViews} showing on the secondary toolbar. If this extra
* is set, the other secondary toolbar configurations will be overriden. The height of the
* {@link RemoteViews} should not exceed 56dp.
* @see CustomTabsIntent.Builder#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent).
*/
public static final String EXTRA_REMOTEVIEWS =
"android.support.customtabs.extra.EXTRA_REMOTEVIEWS";
/**
* Extra that specifies an array of {@link View} ids. When these {@link View}s are clicked, a
* {@link PendingIntent} will be sent, carrying the current url of the custom tab as data.
* <p>
* Note that Custom Tabs will override the default onClick behavior of the listed {@link View}s.
* If you do not care about the current url, you can safely ignore this extra and use
* {@link RemoteViews#setOnClickPendingIntent(int, PendingIntent)} instead.
* @see CustomTabsIntent.Builder#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent).
*/
public static final String EXTRA_REMOTEVIEWS_VIEW_IDS =
"android.support.customtabs.extra.EXTRA_REMOTEVIEWS_VIEW_IDS";
/**
* Extra that specifies the {@link PendingIntent} to be sent when the user clicks on the
* {@link View}s that is listed by {@link #EXTRA_REMOTEVIEWS_VIEW_IDS}.
* <p>
* Note when this {@link PendingIntent} is triggered, it will have the current url as data
* field, also the id of the clicked {@link View}, specified by
* {@link #EXTRA_REMOTEVIEWS_CLICKED_ID}.
* @see CustomTabsIntent.Builder#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent).
*/
public static final String EXTRA_REMOTEVIEWS_PENDINGINTENT =
"android.support.customtabs.extra.EXTRA_REMOTEVIEWS_PENDINGINTENT";
/**
* Extra that specifies which {@link View} has been clicked. This extra will be put to the
* {@link PendingIntent} sent from Custom Tabs when a view in the {@link RemoteViews} is clicked
* @see CustomTabsIntent.Builder#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent).
*/
public static final String EXTRA_REMOTEVIEWS_CLICKED_ID =
"android.support.customtabs.extra.EXTRA_REMOTEVIEWS_CLICKED_ID";
/**
* Extra that specifies whether Instant Apps is enabled.
*/
public static final String EXTRA_ENABLE_INSTANT_APPS =
"android.support.customtabs.extra.EXTRA_ENABLE_INSTANT_APPS";
/**
* Key that specifies the unique ID for an action button. To make a button to show on the
* toolbar, use {@link #TOOLBAR_ACTION_BUTTON_ID} as its ID.
*/
public static final String KEY_ID = "android.support.customtabs.customaction.ID";
/**
* The ID allocated to the custom action button that is shown on the toolbar.
*/
public static final int TOOLBAR_ACTION_BUTTON_ID = 0;
/**
* The maximum allowed number of toolbar items.
*/
private static final int MAX_TOOLBAR_ITEMS = 5;
/**
* An {@link Intent} used to start the Custom Tabs Activity.
*/
@NonNull public final Intent intent;
/**
* A {@link Bundle} containing the start animation for the Custom Tabs Activity.
*/
@Nullable public final Bundle startAnimationBundle;
/**
* Convenience method to launch a Custom Tabs Activity.
* @param context The source Context.
* @param url The URL to load in the Custom Tab.
*/
public void launchUrl(Context context, Uri url) {
intent.setData(url);
ContextCompat.startActivity(context, intent, startAnimationBundle);
}
private CustomTabsIntent(Intent intent, Bundle startAnimationBundle) {
this.intent = intent;
this.startAnimationBundle = startAnimationBundle;
}
/**
* Builder class for {@link CustomTabsIntent} objects.
*/
public static final class Builder {
private final Intent mIntent = new Intent(Intent.ACTION_VIEW);
private ArrayList<Bundle> mMenuItems = null;
private Bundle mStartAnimationBundle = null;
private ArrayList<Bundle> mActionButtons = null;
private boolean mInstantAppsEnabled = true;
/**
* Creates a {@link CustomTabsIntent.Builder} object associated with no
* {@link CustomTabsSession}.
*/
public Builder() {
this(null);
}
/**
* Creates a {@link CustomTabsIntent.Builder} object associated with a given
* {@link CustomTabsSession}.
*
* Guarantees that the {@link Intent} will be sent to the same component as the one the
* session is associated with.
*
* @param session The session to associate this Builder with.
*/
public Builder(@Nullable CustomTabsSession session) {
if (session != null) mIntent.setPackage(session.getComponentName().getPackageName());
Bundle bundle = new Bundle();
BundleCompat.putBinder(
bundle, EXTRA_SESSION, session == null ? null : session.getBinder());
mIntent.putExtras(bundle);
}
/**
* Sets the toolbar color.
*
* @param color {@link Color}
*/
public Builder setToolbarColor(@ColorInt int color) {
mIntent.putExtra(EXTRA_TOOLBAR_COLOR, color);
return this;
}
/**
* Enables the url bar to hide as the user scrolls down on the page.
*/
public Builder enableUrlBarHiding() {
mIntent.putExtra(EXTRA_ENABLE_URLBAR_HIDING, true);
return this;
}
/**
* Sets the Close button icon for the custom tab.
*
* @param icon The icon {@link Bitmap}
*/
public Builder setCloseButtonIcon(@NonNull Bitmap icon) {
mIntent.putExtra(EXTRA_CLOSE_BUTTON_ICON, icon);
return this;
}
/**
* Sets whether the title should be shown in the custom tab.
*
* @param showTitle Whether the title should be shown.
*/
public Builder setShowTitle(boolean showTitle) {
mIntent.putExtra(EXTRA_TITLE_VISIBILITY_STATE,
showTitle ? SHOW_PAGE_TITLE : NO_TITLE);
return this;
}
/**
* Adds a menu item.
*
* @param label Menu label.
* @param pendingIntent Pending intent delivered when the menu item is clicked.
*/
public Builder addMenuItem(@NonNull String label, @NonNull PendingIntent pendingIntent) {
if (mMenuItems == null) mMenuItems = new ArrayList<>();
Bundle bundle = new Bundle();
bundle.putString(KEY_MENU_ITEM_TITLE, label);
bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
mMenuItems.add(bundle);
return this;
}
/**
* Adds a default share item to the menu.
*/
public Builder addDefaultShareMenuItem() {
mIntent.putExtra(EXTRA_DEFAULT_SHARE_MENU_ITEM, true);
return this;
}
/**
* Sets the action button that is displayed in the Toolbar.
* <p>
* This is equivalent to calling
* {@link CustomTabsIntent.Builder#addToolbarItem(int, Bitmap, String, PendingIntent)}
* with {@link #TOOLBAR_ACTION_BUTTON_ID} as id.
*
* @param icon The icon.
* @param description The description for the button. To be used for accessibility.
* @param pendingIntent pending intent delivered when the button is clicked.
* @param shouldTint Whether the action button should be tinted.
*
* @see CustomTabsIntent.Builder#addToolbarItem(int, Bitmap, String, PendingIntent)
*/
public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
@NonNull PendingIntent pendingIntent, boolean shouldTint) {
Bundle bundle = new Bundle();
bundle.putInt(KEY_ID, TOOLBAR_ACTION_BUTTON_ID);
bundle.putParcelable(KEY_ICON, icon);
bundle.putString(KEY_DESCRIPTION, description);
bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
mIntent.putExtra(EXTRA_ACTION_BUTTON_BUNDLE, bundle);
mIntent.putExtra(EXTRA_TINT_ACTION_BUTTON, shouldTint);
return this;
}
/**
* Sets the action button that is displayed in the Toolbar with default tinting behavior.
*
* @see CustomTabsIntent.Builder#setActionButton(
* Bitmap, String, PendingIntent, boolean)
*/
public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
@NonNull PendingIntent pendingIntent) {
return setActionButton(icon, description, pendingIntent, false);
}
/**
* Adds an action button to the custom tab. Multiple buttons can be added via this method.
* If the given id equals {@link #TOOLBAR_ACTION_BUTTON_ID}, the button will be placed on
* the toolbar; if the bitmap is too wide, it will be put to the bottom bar instead. If
* the id is not {@link #TOOLBAR_ACTION_BUTTON_ID}, it will be directly put on secondary
* toolbar. The maximum number of allowed toolbar items in a single intent is
* {@link CustomTabsIntent#getMaxToolbarItems()}. Throws an
* {@link IllegalStateException} when that number is exceeded per intent.
*
* @param id The unique id of the action button. This should be non-negative.
* @param icon The icon.
* @param description The description for the button. To be used for accessibility.
* @param pendingIntent The pending intent delivered when the button is clicked.
*
* @see CustomTabsIntent#getMaxToolbarItems()
* @deprecated Use
* CustomTabsIntent.Builder#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent).
*/
@Deprecated
public Builder addToolbarItem(int id, @NonNull Bitmap icon, @NonNull String description,
PendingIntent pendingIntent) throws IllegalStateException {
if (mActionButtons == null) {
mActionButtons = new ArrayList<>();
}
if (mActionButtons.size() >= MAX_TOOLBAR_ITEMS) {
throw new IllegalStateException(
"Exceeded maximum toolbar item count of " + MAX_TOOLBAR_ITEMS);
}
Bundle bundle = new Bundle();
bundle.putInt(KEY_ID, id);
bundle.putParcelable(KEY_ICON, icon);
bundle.putString(KEY_DESCRIPTION, description);
bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
mActionButtons.add(bundle);
return this;
}
/**
* Sets the color of the secondary toolbar.
* @param color The color for the secondary toolbar.
*/
public Builder setSecondaryToolbarColor(@ColorInt int color) {
mIntent.putExtra(EXTRA_SECONDARY_TOOLBAR_COLOR, color);
return this;
}
/**
* Sets the remote views displayed in the secondary toolbar in a custom tab.
*
* @param remoteViews The {@link RemoteViews} that will be shown on the secondary toolbar.
* @param clickableIDs The IDs of clickable views. The onClick event of these views will be
* handled by custom tabs.
* @param pendingIntent The {@link PendingIntent} that will be sent when the user clicks on
* one of the {@link View}s in clickableIDs. When the
* {@link PendingIntent} is sent, it will have the current URL as its
* intent data.
* @see CustomTabsIntent#EXTRA_REMOTEVIEWS
* @see CustomTabsIntent#EXTRA_REMOTEVIEWS_VIEW_IDS
* @see CustomTabsIntent#EXTRA_REMOTEVIEWS_PENDINGINTENT
* @see CustomTabsIntent#EXTRA_REMOTEVIEWS_CLICKED_ID
*/
public Builder setSecondaryToolbarViews(@NonNull RemoteViews remoteViews,
@Nullable int[] clickableIDs, @Nullable PendingIntent pendingIntent) {
mIntent.putExtra(EXTRA_REMOTEVIEWS, remoteViews);
mIntent.putExtra(EXTRA_REMOTEVIEWS_VIEW_IDS, clickableIDs);
mIntent.putExtra(EXTRA_REMOTEVIEWS_PENDINGINTENT, pendingIntent);
return this;
}
/**
* Sets whether Instant Apps is enabled for this Custom Tab.
* @param enabled Whether Instant Apps should be enabled.
*/
public Builder setInstantAppsEnabled(boolean enabled) {
mInstantAppsEnabled = enabled;
return this;
}
/**
* Sets the start animations.
*
* @param context Application context.
* @param enterResId Resource ID of the "enter" animation for the browser.
* @param exitResId Resource ID of the "exit" animation for the application.
*/
public Builder setStartAnimations(
@NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) {
mStartAnimationBundle = ActivityOptionsCompat.makeCustomAnimation(
context, enterResId, exitResId).toBundle();
return this;
}
/**
* Sets the exit animations.
*
* @param context Application context.
* @param enterResId Resource ID of the "enter" animation for the application.
* @param exitResId Resource ID of the "exit" animation for the browser.
*/
public Builder setExitAnimations(
@NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) {
Bundle bundle = ActivityOptionsCompat.makeCustomAnimation(
context, enterResId, exitResId).toBundle();
mIntent.putExtra(EXTRA_EXIT_ANIMATION_BUNDLE, bundle);
return this;
}
/**
* Combines all the options that have been set and returns a new {@link CustomTabsIntent}
* object.
*/
public CustomTabsIntent build() {
if (mMenuItems != null) {
mIntent.putParcelableArrayListExtra(CustomTabsIntent.EXTRA_MENU_ITEMS, mMenuItems);
}
if (mActionButtons != null) {
mIntent.putParcelableArrayListExtra(EXTRA_TOOLBAR_ITEMS, mActionButtons);
}
mIntent.putExtra(EXTRA_ENABLE_INSTANT_APPS, mInstantAppsEnabled);
return new CustomTabsIntent(mIntent, mStartAnimationBundle);
}
}
/**
* @return The maximum number of allowed toolbar items for
* {@link CustomTabsIntent.Builder#addToolbarItem(int, Bitmap, String, PendingIntent)} and
* {@link CustomTabsIntent#EXTRA_TOOLBAR_ITEMS}.
*/
public static int getMaxToolbarItems() {
return MAX_TOOLBAR_ITEMS;
}
/**
* Adds the necessary flags and extras to signal any browser supporting custom tabs to use the
* browser UI at all times and avoid showing custom tab like UI. Calling this with an intent
* will override any custom tabs related customizations.
* @param intent The intent to modify for always showing browser UI.
* @return The same intent with the necessary flags and extras added.
*/
public static Intent setAlwaysUseBrowserUI(Intent intent) {
if (intent == null) intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_USER_OPT_OUT_FROM_CUSTOM_TABS, true);
return intent;
}
public void setUseNewTask() {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
/**
* Whether a browser receiving the given intent should always use browser UI and avoid using any
* custom tabs UI.
*
* @param intent The intent to check for the required flags and extras.
* @return Whether the browser UI should be used exclusively.
*/
public static boolean shouldAlwaysUseBrowserUI(Intent intent) {
return intent.getBooleanExtra(EXTRA_USER_OPT_OUT_FROM_CUSTOM_TABS, false)
&& (intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0;
}
}

View File

@ -1,271 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import androidx.annotation.IntDef;
import androidx.collection.ArrayMap;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* Abstract service class for implementing Custom Tabs related functionality. The service should
* be responding to the action ACTION_CUSTOM_TABS_CONNECTION. This class should be used by
* implementers that want to provide Custom Tabs functionality, not by clients that want to launch
* Custom Tabs.
*/
public abstract class CustomTabsService extends Service {
/**
* The Intent action that a CustomTabsService must respond to.
*/
public static final String ACTION_CUSTOM_TABS_CONNECTION =
"android.support.customtabs.action.CustomTabsService";
/**
* For {@link CustomTabsService#mayLaunchUrl} calls that wants to specify more than one url,
* this key can be used with {@link Bundle#putParcelable(String, android.os.Parcelable)}
* to insert a new url to each bundle inside list of bundles.
*/
public static final String KEY_URL =
"android.support.customtabs.otherurls.URL";
@Retention(RetentionPolicy.SOURCE)
@IntDef({RESULT_SUCCESS, RESULT_FAILURE_DISALLOWED,
RESULT_FAILURE_REMOTE_ERROR, RESULT_FAILURE_MESSAGING_ERROR})
public @interface Result {
}
/**
* Indicates that the postMessage request was accepted.
*/
public static final int RESULT_SUCCESS = 0;
/**
* Indicates that the postMessage request was not allowed due to a bad argument or requesting
* at a disallowed time like when in background.
*/
public static final int RESULT_FAILURE_DISALLOWED = -1;
/**
* Indicates that the postMessage request has failed due to a {@link RemoteException} .
*/
public static final int RESULT_FAILURE_REMOTE_ERROR = -2;
/**
* Indicates that the postMessage request has failed due to an internal error on the browser
* message channel.
*/
public static final int RESULT_FAILURE_MESSAGING_ERROR = -3;
private final Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() {
@Override
public boolean warmup(long flags) {
return CustomTabsService.this.warmup(flags);
}
@Override
public boolean newSession(ICustomTabsCallback callback) {
final CustomTabsSessionToken sessionToken = new CustomTabsSessionToken(callback);
try {
DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
cleanUpSession(sessionToken);
}
};
synchronized (mDeathRecipientMap) {
callback.asBinder().linkToDeath(deathRecipient, 0);
mDeathRecipientMap.put(callback.asBinder(), deathRecipient);
}
return CustomTabsService.this.newSession(sessionToken);
} catch (RemoteException e) {
return false;
}
}
@Override
public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url,
Bundle extras, List<Bundle> otherLikelyBundles) {
return CustomTabsService.this.mayLaunchUrl(
new CustomTabsSessionToken(callback), url, extras, otherLikelyBundles);
}
@Override
public Bundle extraCommand(String commandName, Bundle args) {
return CustomTabsService.this.extraCommand(commandName, args);
}
@Override
public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) {
return CustomTabsService.this.updateVisuals(
new CustomTabsSessionToken(callback), bundle);
}
@Override
public boolean requestPostMessageChannel(ICustomTabsCallback callback,
Uri postMessageOrigin) {
return CustomTabsService.this.requestPostMessageChannel(
new CustomTabsSessionToken(callback), postMessageOrigin);
}
@Override
public int postMessage(ICustomTabsCallback callback, String message, Bundle extras) {
return CustomTabsService.this.postMessage(
new CustomTabsSessionToken(callback), message, extras);
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* Called when the client side {@link IBinder} for this {@link CustomTabsSessionToken} is dead.
* Can also be used to clean up {@link DeathRecipient} instances allocated for the given token.
*
* @param sessionToken The session token for which the {@link DeathRecipient} call has been
* received.
* @return Whether the clean up was successful. Multiple calls with two tokens holdings the
* same binder will return false.
*/
protected boolean cleanUpSession(CustomTabsSessionToken sessionToken) {
try {
synchronized (mDeathRecipientMap) {
IBinder binder = sessionToken.getCallbackBinder();
DeathRecipient deathRecipient =
mDeathRecipientMap.get(binder);
binder.unlinkToDeath(deathRecipient, 0);
mDeathRecipientMap.remove(binder);
}
} catch (NoSuchElementException e) {
return false;
}
return true;
}
/**
* Warms up the browser process asynchronously.
*
* @param flags Reserved for future use.
* @return Whether warmup was/had been completed successfully. Multiple successful
* calls will return true.
*/
protected abstract boolean warmup(long flags);
/**
* Creates a new session through an ICustomTabsService with the optional callback. This session
* can be used to associate any related communication through the service with an intent and
* then later with a Custom Tab. The client can then send later service calls or intents to
* through same session-intent-Custom Tab association.
*
* @param sessionToken Session token to be used as a unique identifier. This also has access
* to the {@link CustomTabsCallback} passed from the client side through
* {@link CustomTabsSessionToken#getCallback()}.
* @return Whether a new session was successfully created.
*/
protected abstract boolean newSession(CustomTabsSessionToken sessionToken);
/**
* Tells the browser of a likely future navigation to a URL.
* <p>
* The method {@link CustomTabsService#warmup(long)} has to be called beforehand.
* The most likely URL has to be specified explicitly. Optionally, a list of
* other likely URLs can be provided. They are treated as less likely than
* the first one, and have to be sorted in decreasing priority order. These
* additional URLs may be ignored.
* All previous calls to this method will be deprioritized.
*
* @param sessionToken The unique identifier for the session. Can not be null.
* @param url Most likely URL.
* @param extras Reserved for future use.
* @param otherLikelyBundles Other likely destinations, sorted in decreasing
* likelihood order. Each Bundle has to provide a url.
* @return Whether the call was successful.
*/
protected abstract boolean mayLaunchUrl(CustomTabsSessionToken sessionToken, Uri url,
Bundle extras, List<Bundle> otherLikelyBundles);
/**
* Unsupported commands that may be provided by the implementation.
* <p>
* <p>
* <strong>Note:</strong>Clients should <strong>never</strong> rely on this method to have a
* defined behavior, as it is entirely implementation-defined and not supported.
* <p>
* <p> This call can be used by implementations to add extra commands, for testing or
* experimental purposes.
*
* @param commandName Name of the extra command to execute.
* @param args Arguments for the command
* @return The result {@link Bundle}, or null.
*/
protected abstract Bundle extraCommand(String commandName, Bundle args);
/**
* Updates the visuals of custom tabs for the given session. Will only succeed if the given
* session matches the currently active one.
*
* @param sessionToken The currently active session that the custom tab belongs to.
* @param bundle The action button configuration bundle. This bundle should be constructed
* with the same structure in {@link CustomTabsIntent.Builder}.
* @return Whether the operation was successful.
*/
protected abstract boolean updateVisuals(CustomTabsSessionToken sessionToken,
Bundle bundle);
/**
* Sends a request to create a two way postMessage channel between the client and the browser
* linked with the given {@link CustomTabsSession}.
*
* @param sessionToken The unique identifier for the session. Can not be null.
* @param postMessageOrigin A origin that the client is requesting to be identified as
* during the postMessage communication.
* @return Whether the implementation accepted the request. Note that returning true
* here doesn't mean an origin has already been assigned as the validation is
* asynchronous.
*/
protected abstract boolean requestPostMessageChannel(CustomTabsSessionToken sessionToken,
Uri postMessageOrigin);
/**
* Sends a postMessage request using the origin communicated via
* {@link CustomTabsService#requestPostMessageChannel(
*CustomTabsSessionToken, Uri)}. Fails when called before
* {@link PostMessageServiceConnection#notifyMessageChannelReady(Bundle)} is received on the
* client side.
*
* @param sessionToken The unique identifier for the session. Can not be null.
* @param message The message that is being sent.
* @param extras Reserved for future use.
* @return An integer constant about the postMessage request result. Will return
* {@link CustomTabsService#RESULT_SUCCESS} if successful.
*/
@Result
protected abstract int postMessage(
CustomTabsSessionToken sessionToken, String message, Bundle extras);
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
/**
* Abstract {@link ServiceConnection} to use while binding to a {@link CustomTabsService}. Any
* client implementing this is responsible for handling changes related with the lifetime of the
* connection like rebinding on disconnect.
*/
public abstract class CustomTabsServiceConnection implements ServiceConnection {
@Override
public final void onServiceConnected(ComponentName name, IBinder service) {
onCustomTabsServiceConnected(name, new CustomTabsClient(
ICustomTabsService.Stub.asInterface(service), name) {
});
}
/**
* Called when a connection to the {@link CustomTabsService} has been established.
* @param name The concrete component name of the service that has been connected.
* @param client {@link CustomTabsClient} that contains the {@link IBinder} with which the
* connection have been established. All further communication should be initiated
* using this client.
*/
public abstract void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client);
}

View File

@ -1,204 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.View;
import android.widget.RemoteViews;
import java.util.List;
/**
* A class to be used for Custom Tabs related communication. Clients that want to launch Custom Tabs
* can use this class exclusively to handle all related communication.
*/
public final class CustomTabsSession {
private static final String TAG = "CustomTabsSession";
private final Object mLock = new Object();
private final ICustomTabsService mService;
private final ICustomTabsCallback mCallback;
private final ComponentName mComponentName;
/**
* Provides browsers a way to generate a dummy {@link CustomTabsSession} for testing
* purposes.
*
* @param componentName The component the session should be created for.
* @return A dummy session with no functionality.
*/
public static CustomTabsSession createDummySessionForTesting(ComponentName componentName) {
return new CustomTabsSession(null, new CustomTabsSessionToken.DummyCallback(), componentName);
}
/* package */ CustomTabsSession(
ICustomTabsService service, ICustomTabsCallback callback, ComponentName componentName) {
mService = service;
mCallback = callback;
mComponentName = componentName;
}
/**
* Tells the browser of a likely future navigation to a URL.
* The most likely URL has to be specified first. Optionally, a list of
* other likely URLs can be provided. They are treated as less likely than
* the first one, and have to be sorted in decreasing priority order. These
* additional URLs may be ignored.
* All previous calls to this method will be deprioritized.
*
* @param url Most likely URL.
* @param extras Reserved for future use.
* @param otherLikelyBundles Other likely destinations, sorted in decreasing
* likelihood order. Inside each Bundle, the client should provide a
* {@link Uri} using {@link CustomTabsService#KEY_URL} with
* {@link Bundle#putParcelable(String, android.os.Parcelable)}.
* @return true for success.
*/
public boolean mayLaunchUrl(Uri url, Bundle extras, List<Bundle> otherLikelyBundles) {
try {
return mService.mayLaunchUrl(mCallback, url, extras, otherLikelyBundles);
} catch (RemoteException e) {
return false;
}
}
/**
* This sets the action button on the toolbar with ID
* {@link CustomTabsIntent#TOOLBAR_ACTION_BUTTON_ID}.
*
* @param icon The new icon of the action button.
* @param description Content description of the action button.
*
* @see CustomTabsSession#setToolbarItem(int, Bitmap, String)
*/
public boolean setActionButton(@NonNull Bitmap icon, @NonNull String description) {
Bundle bundle = new Bundle();
bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
Bundle metaBundle = new Bundle();
metaBundle.putBundle(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundle);
try {
return mService.updateVisuals(mCallback, metaBundle);
} catch (RemoteException e) {
return false;
}
}
/**
* Updates the {@link RemoteViews} of the secondary toolbar in an existing custom tab session.
* @param remoteViews The updated {@link RemoteViews} that will be shown in secondary toolbar.
* If null, the current secondary toolbar will be dismissed.
* @param clickableIDs The ids of clickable views. The onClick event of these views will be
* handled by custom tabs.
* @param pendingIntent The {@link PendingIntent} that will be sent when the user clicks on one
* of the {@link View}s in clickableIDs.
*/
public boolean setSecondaryToolbarViews(@Nullable RemoteViews remoteViews,
@Nullable int[] clickableIDs, @Nullable PendingIntent pendingIntent) {
Bundle bundle = new Bundle();
bundle.putParcelable(CustomTabsIntent.EXTRA_REMOTEVIEWS, remoteViews);
bundle.putIntArray(CustomTabsIntent.EXTRA_REMOTEVIEWS_VIEW_IDS, clickableIDs);
bundle.putParcelable(CustomTabsIntent.EXTRA_REMOTEVIEWS_PENDINGINTENT, pendingIntent);
try {
return mService.updateVisuals(mCallback, bundle);
} catch (RemoteException e) {
return false;
}
}
/**
* Updates the visuals for toolbar items. Will only succeed if a custom tab created using this
* session is in the foreground in browser and the given id is valid.
* @param id The id for the item to update.
* @param icon The new icon of the toolbar item.
* @param description Content description of the toolbar item.
* @return Whether the update succeeded.
* @deprecated Use
* CustomTabsSession#setSecondaryToolbarViews(RemoteViews, int[], PendingIntent)
*/
@Deprecated
public boolean setToolbarItem(int id, @NonNull Bitmap icon, @NonNull String description) {
Bundle bundle = new Bundle();
bundle.putInt(CustomTabsIntent.KEY_ID, id);
bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
Bundle metaBundle = new Bundle();
metaBundle.putBundle(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundle);
try {
return mService.updateVisuals(mCallback, metaBundle);
} catch (RemoteException e) {
return false;
}
}
/**
* Sends a request to create a two way postMessage channel between the client and the browser.
*
* @param postMessageOrigin A origin that the client is requesting to be identified as
* during the postMessage communication.
* @return Whether the implementation accepted the request. Note that returning true
* here doesn't mean an origin has already been assigned as the validation is
* asynchronous.
*/
public boolean requestPostMessageChannel(Uri postMessageOrigin) {
try {
return mService.requestPostMessageChannel(
mCallback, postMessageOrigin);
} catch (RemoteException e) {
return false;
}
}
/**
* Sends a postMessage request using the origin communicated via
* {@link CustomTabsService#requestPostMessageChannel(
* CustomTabsSessionToken, Uri)}. Fails when called before
* {@link PostMessageServiceConnection#notifyMessageChannelReady(Bundle)} is received on
* the client side.
*
* @param message The message that is being sent.
* @param extras Reserved for future use.
* @return An integer constant about the postMessage request result. Will return
* {@link CustomTabsService#RESULT_SUCCESS} if successful.
*/
public int postMessage(String message, Bundle extras) {
synchronized (mLock) {
try {
return mService.postMessage(mCallback, message, extras);
} catch (RemoteException e) {
return CustomTabsService.RESULT_FAILURE_REMOTE_ERROR;
}
}
}
/* package */ IBinder getBinder() {
return mCallback.asBinder();
}
/* package */ ComponentName getComponentName() {
return mComponentName;
}
}

View File

@ -1,150 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.core.app.BundleCompat;
import android.util.Log;
/**
* Wrapper class that can be used as a unique identifier for a session. Also contains an accessor
* for the {@link CustomTabsCallback} for the session if there was any.
*/
public class CustomTabsSessionToken {
private static final String TAG = "CustomTabsSessionToken";
private final ICustomTabsCallback mCallbackBinder;
private final CustomTabsCallback mCallback;
/* package */ static class DummyCallback extends ICustomTabsCallback.Stub {
@Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {}
@Override
public void extraCallback(String callbackName, Bundle args) {}
@Override
public void onMessageChannelReady(Bundle extras) {}
@Override
public void onPostMessage(String message, Bundle extras) {}
@Override
public IBinder asBinder() {
return this;
}
}
/**
* Obtain a {@link CustomTabsSessionToken} from an intent. See {@link CustomTabsIntent.Builder}
* for ways to generate an intent for custom tabs.
* @param intent The intent to generate the token from. This has to include an extra for
* {@link CustomTabsIntent#EXTRA_SESSION}.
* @return The token that was generated.
*/
public static CustomTabsSessionToken getSessionTokenFromIntent(Intent intent) {
Bundle b = intent.getExtras();
IBinder binder = BundleCompat.getBinder(b, CustomTabsIntent.EXTRA_SESSION);
if (binder == null) return null;
return new CustomTabsSessionToken(ICustomTabsCallback.Stub.asInterface(binder));
}
/**
* Provides browsers a way to generate a dummy {@link CustomTabsSessionToken} for testing
* purposes.
*
* @return A dummy token with no functionality.
*/
public static CustomTabsSessionToken createDummySessionTokenForTesting() {
return new CustomTabsSessionToken(new DummyCallback());
}
CustomTabsSessionToken(ICustomTabsCallback callbackBinder) {
mCallbackBinder = callbackBinder;
mCallback = new CustomTabsCallback() {
@Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {
try {
mCallbackBinder.onNavigationEvent(navigationEvent, extras);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
}
}
@Override
public void extraCallback(String callbackName, Bundle args) {
try {
mCallbackBinder.extraCallback(callbackName, args);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
}
}
@Override
public void onMessageChannelReady(Bundle extras) {
try {
mCallbackBinder.onMessageChannelReady(extras);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
}
}
@Override
public void onPostMessage(String message, Bundle extras) {
try {
mCallbackBinder.onPostMessage(message, extras);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
}
}
};
}
IBinder getCallbackBinder() {
return mCallbackBinder.asBinder();
}
@Override
public int hashCode() {
return getCallbackBinder().hashCode();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof CustomTabsSessionToken)) return false;
CustomTabsSessionToken token = (CustomTabsSessionToken) o;
return token.getCallbackBinder().equals(mCallbackBinder.asBinder());
}
/**
* @return {@link CustomTabsCallback} corresponding to this session if there was any non-null
* callbacks passed by the client.
*/
public CustomTabsCallback getCallback() {
return mCallback;
}
/**
* @return Whether this token is associated with the given session.
*/
public boolean isAssociatedWith(CustomTabsSession session) {
return session.getBinder().equals(mCallbackBinder);
}
}

View File

@ -1,226 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
public interface ICustomTabsCallback extends IInterface {
void onNavigationEvent(int var1, Bundle var2) throws RemoteException;
void extraCallback(String var1, Bundle var2) throws RemoteException;
void onMessageChannelReady(Bundle var1) throws RemoteException;
void onPostMessage(String var1, Bundle var2) throws RemoteException;
abstract class Stub extends Binder implements ICustomTabsCallback {
private static final String DESCRIPTOR = "android.support.customtabs.ICustomTabsCallback";
static final int TRANSACTION_onNavigationEvent = 2;
static final int TRANSACTION_extraCallback = 3;
static final int TRANSACTION_onMessageChannelReady = 4;
static final int TRANSACTION_onPostMessage = 5;
public Stub() {
this.attachInterface(this, "android.support.customtabs.ICustomTabsCallback");
}
public static ICustomTabsCallback asInterface(IBinder obj) {
if(obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("android.support.customtabs.ICustomTabsCallback");
return (iin != null && iin instanceof ICustomTabsCallback?(ICustomTabsCallback)iin:new ICustomTabsCallback.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
String _arg0;
Bundle _arg1;
switch(code) {
case 2:
data.enforceInterface("android.support.customtabs.ICustomTabsCallback");
int _arg02 = data.readInt();
if(0 != data.readInt()) {
_arg1 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg1 = null;
}
this.onNavigationEvent(_arg02, _arg1);
reply.writeNoException();
return true;
case 3:
data.enforceInterface("android.support.customtabs.ICustomTabsCallback");
_arg0 = data.readString();
if(0 != data.readInt()) {
_arg1 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg1 = null;
}
this.extraCallback(_arg0, _arg1);
reply.writeNoException();
return true;
case 4:
data.enforceInterface("android.support.customtabs.ICustomTabsCallback");
Bundle _arg01;
if(0 != data.readInt()) {
_arg01 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg01 = null;
}
this.onMessageChannelReady(_arg01);
reply.writeNoException();
return true;
case 5:
data.enforceInterface("android.support.customtabs.ICustomTabsCallback");
_arg0 = data.readString();
if(0 != data.readInt()) {
_arg1 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg1 = null;
}
this.onPostMessage(_arg0, _arg1);
reply.writeNoException();
return true;
case 1598968902:
reply.writeString("android.support.customtabs.ICustomTabsCallback");
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements ICustomTabsCallback {
private IBinder mRemote;
Proxy(IBinder remote) {
this.mRemote = remote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "android.support.customtabs.ICustomTabsCallback";
}
public void onNavigationEvent(int navigationEvent, Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback");
_data.writeInt(navigationEvent);
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(2, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void extraCallback(String callbackName, Bundle args) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback");
_data.writeString(callbackName);
if(args != null) {
_data.writeInt(1);
args.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(3, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void onMessageChannelReady(Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback");
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(4, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void onPostMessage(String message, Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback");
_data.writeString(message);
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(5, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
}

View File

@ -1,377 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
public interface ICustomTabsService extends IInterface {
boolean warmup(long var1) throws RemoteException;
boolean newSession(ICustomTabsCallback var1) throws RemoteException;
boolean mayLaunchUrl(ICustomTabsCallback var1, Uri var2, Bundle var3, List<Bundle> var4) throws RemoteException;
Bundle extraCommand(String var1, Bundle var2) throws RemoteException;
boolean updateVisuals(ICustomTabsCallback var1, Bundle var2) throws RemoteException;
boolean requestPostMessageChannel(ICustomTabsCallback var1, Uri var2) throws RemoteException;
int postMessage(ICustomTabsCallback var1, String var2, Bundle var3) throws RemoteException;
abstract class Stub extends Binder implements ICustomTabsService {
private static final String DESCRIPTOR = "android.support.customtabs.ICustomTabsService";
static final int TRANSACTION_warmup = 2;
static final int TRANSACTION_newSession = 3;
static final int TRANSACTION_mayLaunchUrl = 4;
static final int TRANSACTION_extraCommand = 5;
static final int TRANSACTION_updateVisuals = 6;
static final int TRANSACTION_requestPostMessageChannel = 7;
static final int TRANSACTION_postMessage = 8;
public Stub() {
this.attachInterface(this, "android.support.customtabs.ICustomTabsService");
}
public static ICustomTabsService asInterface(IBinder obj) {
if(obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("android.support.customtabs.ICustomTabsService");
return (iin != null && iin instanceof ICustomTabsService?(ICustomTabsService)iin:new ICustomTabsService.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
ICustomTabsCallback _arg0;
Bundle _arg2;
Uri _arg11;
Bundle _arg12;
boolean _arg21;
switch(code) {
case 2:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
long _arg02 = data.readLong();
_arg21 = this.warmup(_arg02);
reply.writeNoException();
reply.writeInt(_arg21?1:0);
return true;
case 3:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
boolean _arg13 = this.newSession(_arg0);
reply.writeNoException();
reply.writeInt(_arg13?1:0);
return true;
case 4:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
if(0 != data.readInt()) {
_arg11 = Uri.CREATOR.createFromParcel(data);
} else {
_arg11 = null;
}
if(0 != data.readInt()) {
_arg2 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg2 = null;
}
ArrayList _result2 = data.createTypedArrayList(Bundle.CREATOR);
boolean _result1 = this.mayLaunchUrl(_arg0, _arg11, _arg2, _result2);
reply.writeNoException();
reply.writeInt(_result1?1:0);
return true;
case 5:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
String _arg01 = data.readString();
if(0 != data.readInt()) {
_arg12 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg12 = null;
}
_arg2 = this.extraCommand(_arg01, _arg12);
reply.writeNoException();
if(_arg2 != null) {
reply.writeInt(1);
_arg2.writeToParcel(reply, 1);
} else {
reply.writeInt(0);
}
return true;
case 6:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
if(0 != data.readInt()) {
_arg12 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg12 = null;
}
_arg21 = this.updateVisuals(_arg0, _arg12);
reply.writeNoException();
reply.writeInt(_arg21?1:0);
return true;
case 7:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
if(0 != data.readInt()) {
_arg11 = Uri.CREATOR.createFromParcel(data);
} else {
_arg11 = null;
}
_arg21 = this.requestPostMessageChannel(_arg0, _arg11);
reply.writeNoException();
reply.writeInt(_arg21?1:0);
return true;
case 8:
data.enforceInterface("android.support.customtabs.ICustomTabsService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
String _arg1 = data.readString();
if(0 != data.readInt()) {
_arg2 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg2 = null;
}
int _result = this.postMessage(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(_result);
return true;
case 1598968902:
reply.writeString("android.support.customtabs.ICustomTabsService");
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements ICustomTabsService {
private IBinder mRemote;
Proxy(IBinder remote) {
this.mRemote = remote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "android.support.customtabs.ICustomTabsService";
}
public boolean warmup(long flags) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeLong(flags);
this.mRemote.transact(2, _data, _reply, 0);
_reply.readException();
_result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public boolean newSession(ICustomTabsCallback callback) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
this.mRemote.transact(3, _data, _reply, 0);
_reply.readException();
_result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url, Bundle extras, List<Bundle> otherLikelyBundles) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
if(url != null) {
_data.writeInt(1);
url.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
_data.writeTypedList(otherLikelyBundles);
this.mRemote.transact(4, _data, _reply, 0);
_reply.readException();
_result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public Bundle extraCommand(String commandName, Bundle args) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
Bundle _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeString(commandName);
if(args != null) {
_data.writeInt(1);
args.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(5, _data, _reply, 0);
_reply.readException();
if(0 != _reply.readInt()) {
_result = Bundle.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
if(bundle != null) {
_data.writeInt(1);
bundle.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(6, _data, _reply, 0);
_reply.readException();
_result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public boolean requestPostMessageChannel(ICustomTabsCallback callback, Uri postMessageOrigin) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
if(postMessageOrigin != null) {
_data.writeInt(1);
postMessageOrigin.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(7, _data, _reply, 0);
_reply.readException();
_result = 0 != _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public int postMessage(ICustomTabsCallback callback, String message, Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken("android.support.customtabs.ICustomTabsService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
_data.writeString(message);
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(8, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
}
}

View File

@ -1,155 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.
*/
package org.telegram.messenger.support.customtabs;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
public interface IPostMessageService extends IInterface {
void onMessageChannelReady(ICustomTabsCallback var1, Bundle var2) throws RemoteException;
void onPostMessage(ICustomTabsCallback var1, String var2, Bundle var3) throws RemoteException;
abstract class Stub extends Binder implements IPostMessageService {
private static final String DESCRIPTOR = "android.support.customtabs.IPostMessageService";
static final int TRANSACTION_onMessageChannelReady = 2;
static final int TRANSACTION_onPostMessage = 3;
public Stub() {
this.attachInterface(this, "android.support.customtabs.IPostMessageService");
}
public static IPostMessageService asInterface(IBinder obj) {
if(obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("android.support.customtabs.IPostMessageService");
return (iin != null && iin instanceof IPostMessageService?(IPostMessageService)iin:new IPostMessageService.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
ICustomTabsCallback _arg0;
switch(code) {
case 2:
data.enforceInterface("android.support.customtabs.IPostMessageService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
Bundle _arg11;
if(0 != data.readInt()) {
_arg11 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg11 = null;
}
this.onMessageChannelReady(_arg0, _arg11);
reply.writeNoException();
return true;
case 3:
data.enforceInterface("android.support.customtabs.IPostMessageService");
_arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder());
String _arg1 = data.readString();
Bundle _arg2;
if(0 != data.readInt()) {
_arg2 = Bundle.CREATOR.createFromParcel(data);
} else {
_arg2 = null;
}
this.onPostMessage(_arg0, _arg1, _arg2);
reply.writeNoException();
return true;
case 1598968902:
reply.writeString("android.support.customtabs.IPostMessageService");
return true;
default:
return super.onTransact(code, data, reply, flags);
}
}
private static class Proxy implements IPostMessageService {
private IBinder mRemote;
Proxy(IBinder remote) {
this.mRemote = remote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "android.support.customtabs.IPostMessageService";
}
public void onMessageChannelReady(ICustomTabsCallback callback, Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.IPostMessageService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(2, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
public void onPostMessage(ICustomTabsCallback callback, String message, Bundle extras) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken("android.support.customtabs.IPostMessageService");
_data.writeStrongBinder(callback != null?callback.asBinder():null);
_data.writeString(message);
if(extras != null) {
_data.writeInt(1);
extras.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
this.mRemote.transact(3, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
}

View File

@ -1,40 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.messenger.support.customtabs;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
/**
* A service to receive postMessage related communication from a Custom Tabs provider.
*/
public class PostMessageService extends Service {
private IPostMessageService.Stub mBinder = new IPostMessageService.Stub() {
@Override
public void onMessageChannelReady(
ICustomTabsCallback callback, Bundle extras) throws RemoteException {
callback.onMessageChannelReady(extras);
}
@Override
public void onPostMessage(ICustomTabsCallback callback,
String message, Bundle extras) throws RemoteException {
callback.onPostMessage(message, extras);
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}

View File

@ -1,118 +0,0 @@
/*
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2018.
*/
package org.telegram.messenger.support.customtabs;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
/**
* A {@link ServiceConnection} for Custom Tabs providers to use while connecting to a
* {@link PostMessageService} on the client side.
*/
public abstract class PostMessageServiceConnection implements ServiceConnection {
private final Object mLock = new Object();
private final ICustomTabsCallback mSessionBinder;
private IPostMessageService mService;
public PostMessageServiceConnection(CustomTabsSessionToken session) {
mSessionBinder = ICustomTabsCallback.Stub.asInterface(session.getCallbackBinder());
}
/**
* Binds the browser side to the client app through the given {@link PostMessageService} name.
* After this, this {@link PostMessageServiceConnection} can be used for sending postMessage
* related communication back to the client.
* @param context A context to bind to the service.
* @param packageName The name of the package to be bound to.
* @return Whether the binding was successful.
*/
public boolean bindSessionToPostMessageService(Context context, String packageName) {
Intent intent = new Intent();
intent.setClassName(packageName, PostMessageService.class.getName());
return context.bindService(intent, this, Context.BIND_AUTO_CREATE);
}
/**
* Unbinds this service connection from the given context.
* @param context The context to be unbound from.
*/
public void unbindFromContext(Context context) {
context.unbindService(this);
}
@Override
public final void onServiceConnected(ComponentName name, IBinder service) {
mService = IPostMessageService.Stub.asInterface(service);
onPostMessageServiceConnected();
}
@Override
public final void onServiceDisconnected(ComponentName name) {
mService = null;
onPostMessageServiceDisconnected();
}
/**
* Notifies the client that the postMessage channel requested with
* {@link CustomTabsService#requestPostMessageChannel(
* CustomTabsSessionToken, android.net.Uri)} is ready. This method should be
* called when the browser binds to the client side {@link PostMessageService} and also readies
* a connection to the web frame.
*
* @param extras Reserved for future use.
* @return Whether the notification was sent to the remote successfully.
*/
public final boolean notifyMessageChannelReady(Bundle extras) {
if (mService == null) return false;
synchronized (mLock) {
try {
mService.onMessageChannelReady(mSessionBinder, extras);
} catch (RemoteException e) {
return false;
}
}
return true;
}
/**
* Posts a message to the client. This should be called when a tab controlled by related
* {@link CustomTabsSession} has sent a postMessage. If postMessage() is called from a single
* thread, then the messages will be posted in the same order.
*
* @param message The message sent.
* @param extras Reserved for future use.
* @return Whether the postMessage was sent to the remote successfully.
*/
public final boolean postMessage(String message, Bundle extras) {
if (mService == null) return false;
synchronized (mLock) {
try {
mService.onPostMessage(mSessionBinder, message, extras);
} catch (RemoteException e) {
return false;
}
}
return true;
}
/**
* Called when the {@link PostMessageService} connection is established.
*/
public void onPostMessageServiceConnected() {}
/**
* Called when the connection is lost with the {@link PostMessageService}.
*/
public void onPostMessageServiceDisconnected() {}
}

View File

@ -16,8 +16,8 @@ package org.telegram.messenger.support.customtabsclient.shared;
import android.content.ComponentName;
import org.telegram.messenger.support.customtabs.CustomTabsClient;
import org.telegram.messenger.support.customtabs.CustomTabsServiceConnection;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsServiceConnection;
import java.lang.ref.WeakReference;

View File

@ -14,7 +14,7 @@
package org.telegram.messenger.support.customtabsclient.shared;
import org.telegram.messenger.support.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsClient;
/**
* Callback for events when connecting and disconnecting from Custom Tabs Service.