| /* |
| * Copyright (C) 2018 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 androidx.sharetarget; |
| |
| import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; |
| |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.IntentFilter; |
| import android.os.Bundle; |
| import android.util.Log; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.RequiresApi; |
| import androidx.annotation.RestrictTo; |
| import androidx.annotation.VisibleForTesting; |
| import androidx.core.content.pm.ShortcutInfoCompat; |
| import androidx.core.content.pm.ShortcutManagerCompat; |
| import androidx.core.graphics.drawable.IconCompat; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** |
| * Provides direct share items to the system, by cross checking dynamic shortcuts from |
| * ShortcutManagerCompat and share target definitions from a Xml resource. Used for backward |
| * compatibility to push share targets to shortcut manager on older SDKs. |
| * |
| * @hide |
| */ |
| @RequiresApi(23) |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| @SuppressWarnings("deprecation") |
| public class ChooserTargetServiceCompat extends android.service.chooser.ChooserTargetService { |
| |
| static final String TAG = "ChooserServiceCompat"; |
| |
| @Override |
| public List<android.service.chooser.ChooserTarget> onGetChooserTargets( |
| ComponentName targetActivityName, IntentFilter matchedFilter) { |
| Context context = getApplicationContext(); |
| |
| // Retrieve share targets |
| List<ShareTargetCompat> targets = ShareTargetXmlParser.getShareTargets(context); |
| List<ShareTargetCompat> matchedTargets = new ArrayList<>(); |
| for (ShareTargetCompat target : targets) { |
| if (!target.mTargetClass.equals(targetActivityName.getClassName())) { |
| continue; |
| } |
| for (ShareTargetCompat.TargetData data : target.mTargetData) { |
| if (matchedFilter.hasDataType(data.mMimeType)) { |
| // Matched at least with one data type (OR operation) |
| matchedTargets.add(target); |
| break; |
| } |
| } |
| } |
| if (matchedTargets.isEmpty()) { |
| return Collections.emptyList(); |
| } |
| |
| // Retrieve shortcuts |
| ShortcutInfoCompatSaverImpl shortcutSaver = |
| ShortcutInfoCompatSaverImpl.getInstance(context); |
| List<ShortcutInfoCompat> shortcuts; |
| try { |
| shortcuts = shortcutSaver.getShortcuts(); |
| } catch (Exception e) { |
| Log.e(TAG, "Failed to retrieve shortcuts: ", e); |
| return Collections.emptyList(); |
| } |
| if (shortcuts == null || shortcuts.isEmpty()) { |
| return Collections.emptyList(); |
| } |
| |
| // List of matched shortcuts with their target component names |
| List<ShortcutHolder> matchedShortcuts = new ArrayList<>(); |
| for (ShortcutInfoCompat shortcut : shortcuts) { |
| for (ShareTargetCompat item : matchedTargets) { |
| // Shortcut must have all the share target's categories (AND operation) |
| if (shortcut.getCategories().containsAll(Arrays.asList(item.mCategories))) { |
| matchedShortcuts.add(new ShortcutHolder(shortcut, |
| new ComponentName(context.getPackageName(), item.mTargetClass))); |
| break; |
| } |
| } |
| } |
| return convertShortcutsToChooserTargets(shortcutSaver, matchedShortcuts); |
| } |
| |
| @VisibleForTesting |
| @NonNull |
| static List<android.service.chooser.ChooserTarget> convertShortcutsToChooserTargets( |
| @NonNull ShortcutInfoCompatSaverImpl shortcutSaver, |
| @NonNull List<ShortcutHolder> matchedShortcuts) { |
| if (matchedShortcuts.isEmpty()) { |
| return new ArrayList<>(); |
| } |
| Collections.sort(matchedShortcuts); |
| |
| ArrayList<android.service.chooser.ChooserTarget> chooserTargets = new ArrayList<>(); |
| float currentScore = 1.0f; |
| int lastRank = matchedShortcuts.get(0).getShortcut().getRank(); |
| for (ShortcutHolder holder : matchedShortcuts) { |
| final ShortcutInfoCompat shortcut = holder.getShortcut(); |
| IconCompat shortcutIcon; |
| try { |
| shortcutIcon = shortcutSaver.getShortcutIcon(shortcut.getId()); |
| } catch (Exception e) { |
| Log.e(TAG, "Failed to retrieve shortcut icon: ", e); |
| shortcutIcon = null; |
| } |
| |
| Bundle extras = new Bundle(); |
| extras.putString(ShortcutManagerCompat.EXTRA_SHORTCUT_ID, shortcut.getId()); |
| |
| if (lastRank != shortcut.getRank()) { |
| currentScore -= 0.01f; |
| lastRank = shortcut.getRank(); |
| } |
| chooserTargets.add(new android.service.chooser.ChooserTarget( |
| shortcut.getShortLabel(), |
| shortcutIcon == null ? null : shortcutIcon.toIcon(), |
| currentScore, |
| holder.getTargetClass(), |
| extras)); |
| } |
| |
| return chooserTargets; |
| } |
| |
| static class ShortcutHolder implements Comparable<ShortcutHolder> { |
| private final ShortcutInfoCompat mShortcut; |
| private final ComponentName mTargetClass; |
| |
| ShortcutHolder(ShortcutInfoCompat shortcut, ComponentName targetClass) { |
| mShortcut = shortcut; |
| mTargetClass = targetClass; |
| } |
| |
| ShortcutInfoCompat getShortcut() { |
| return mShortcut; |
| } |
| |
| ComponentName getTargetClass() { |
| return mTargetClass; |
| } |
| |
| @Override |
| public int compareTo(ShortcutHolder other) { |
| return this.getShortcut().getRank() - other.getShortcut().getRank(); |
| } |
| } |
| } |