1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.PackageInfo; 23 import android.content.pm.PackageManager; 24 import android.net.Uri; 25 import android.text.TextUtils; 26 import android.util.Log; 27 import android.view.View; 28 29 import androidx.core.content.FileProvider; 30 31 import com.android.launcher3.model.data.ItemInfo; 32 import com.android.launcher3.popup.SystemShortcut; 33 34 import java.io.File; 35 36 /** 37 * Defines the Share system shortcut and its factory. 38 * This shortcut can be added to the app long-press menu on the home screen. 39 * Clicking the button will initiate peer-to-peer sharing of the app. 40 */ 41 public final class AppSharing { 42 /** 43 * This flag enables this feature. It is defined here rather than in launcher3's FeatureFlags 44 * because it is unique to Go and not toggleable at runtime. 45 */ 46 public static final boolean ENABLE_APP_SHARING = true; 47 48 private static final String TAG = "AppSharing"; 49 private static final String FILE_PROVIDER_SUFFIX = ".overview.fileprovider"; 50 private static final String APP_EXSTENSION = ".apk"; 51 private static final String APP_MIME_TYPE = "application/application"; 52 53 private final String mSharingComponent; 54 AppSharing(Launcher launcher)55 private AppSharing(Launcher launcher) { 56 mSharingComponent = launcher.getText(R.string.app_sharing_component).toString(); 57 } 58 canShare(ItemInfo info)59 private boolean canShare(ItemInfo info) { 60 /** 61 * TODO: Implement once b/168831749 has been resolved 62 * The implementation should check the validity of the app. 63 * It should also check whether the app is free or paid, returning false in the latter case. 64 * For now, all checks occur in the sharing app. 65 * So, we simply check whether the sharing app is defined. 66 */ 67 return !TextUtils.isEmpty(mSharingComponent); 68 } 69 getShareableUri(Context context, String path, String displayName)70 private Uri getShareableUri(Context context, String path, String displayName) { 71 String authority = BuildConfig.APPLICATION_ID + FILE_PROVIDER_SUFFIX; 72 File pathFile = new File(path); 73 return FileProvider.getUriForFile(context, authority, pathFile, displayName); 74 } 75 getShortcut(Launcher launcher, ItemInfo info)76 private SystemShortcut<Launcher> getShortcut(Launcher launcher, ItemInfo info) { 77 if (!canShare(info)) { 78 return null; 79 } 80 81 return new Share(launcher, info); 82 } 83 84 /** 85 * The Share App system shortcut, used to initiate p2p sharing of a given app 86 */ 87 public final class Share extends SystemShortcut<Launcher> { Share(Launcher target, ItemInfo itemInfo)88 public Share(Launcher target, ItemInfo itemInfo) { 89 super(R.drawable.ic_share, R.string.app_share_drop_target_label, target, itemInfo); 90 } 91 92 @Override onClick(View view)93 public void onClick(View view) { 94 Intent sendIntent = new Intent(); 95 sendIntent.setAction(Intent.ACTION_SEND); 96 97 ComponentName targetComponent = mItemInfo.getTargetComponent(); 98 if (targetComponent == null) { 99 Log.e(TAG, "Item missing target component"); 100 return; 101 } 102 String packageName = targetComponent.getPackageName(); 103 PackageManager packageManager = view.getContext().getPackageManager(); 104 String sourceDir, appLabel; 105 try { 106 PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0); 107 sourceDir = packageInfo.applicationInfo.sourceDir; 108 appLabel = packageManager.getApplicationLabel(packageInfo.applicationInfo) 109 .toString() + APP_EXSTENSION; 110 } catch (Exception e) { 111 Log.e(TAG, "Could not find info for package \"" + packageName + "\""); 112 return; 113 } 114 Uri uri = getShareableUri(view.getContext(), sourceDir, appLabel); 115 sendIntent.putExtra(Intent.EXTRA_STREAM, uri); 116 sendIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); 117 118 sendIntent.setType(APP_MIME_TYPE); 119 sendIntent.setComponent(ComponentName.unflattenFromString(mSharingComponent)); 120 121 mTarget.startActivitySafely(view, sendIntent, mItemInfo); 122 123 AbstractFloatingView.closeAllOpenViews(mTarget); 124 } 125 } 126 127 /** 128 * Shortcut factory for generating the Share App button 129 */ 130 public static final SystemShortcut.Factory<Launcher> SHORTCUT_FACTORY = (launcher, itemInfo) -> 131 (new AppSharing(launcher)).getShortcut(launcher, itemInfo); 132 } 133