searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

android13剪切板新增功能

2024-04-29 01:41:31
24
0

剪切板主要框架

官方给出的剪切板主要框架:

 

从 Android 13 开始,将内容添加到剪贴板时,系统会显示标准视觉确认界面。新确认界面会执行以下操作:

  • 确认内容已成功复制。
  • 提供所复制内容的预览。

下面看看实现方式:

新增功能主要流程分析

通过查看搜索,发现剪切板弹框出现在systemuiapp中,源码的位置:
frameworks/base/packages/SystemUI/src/com/android/systemui/clipboardoverlay/
可以看到该目录下存在几个文件:

ClipboardListener.java //用来监听剪切板事件
ClipboardOverlayController.java  //控制UI显示
ClipboardOverlayControllerFactory.java //控制UI显示工厂类
ClipboardOverlayEvent.java //显示消息
EditTextActivity.java //编辑界面

当剪切板变化时候,ClipBoradListener中会监听到剪切板事件,并回调到Listener中的onPrimaryClipChanged事件:

public void onPrimaryClipChanged() {
          if (!mClipboardManager.hasPrimaryClip()) {
              return;
          }
  
          String clipSource = mClipboardManager.getPrimaryClipSource();
          ClipData clipData = mClipboardManager.getPrimaryClip();
  
          if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) {
              Log.i(TAG, "Clipboard overlay suppressed.");
              return;
          }
  
          if (mClipboardOverlayController == null) {
              mClipboardOverlayController = mOverlayFactory.create(mContext);
              mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
          } else {
              mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
          }
          mClipboardOverlayController.setClipData(clipData, clipSource);
          mClipboardOverlayController.setOnSessionCompleteListener(() -> {
              // Session is complete, free memory until it's needed again.
              mClipboardOverlayController = null;
          });
      }

可以看到,对支持Overlay的类型,都会走到ClipboardOverlayController的处理中,这里主要看下setClipData的处理:

 void setClipData(ClipData clipData, String clipSource) {
          ....         
          if (clipData == null || clipData.getItemCount() == 0) {
              showTextPreview(
                      mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
                      mTextPreview);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
          } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
              ClipData.Item item = clipData.getItemAt(0);
              if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                      CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
                  if (item.getTextLinks() != null) {
                      AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
                  }
              }
              if (isSensitive) {
                  showEditableText(
                          mContext.getResources().getString(R.string.clipboard_asterisks), true);
              } else {
                  showEditableText(item.getText(), false);
              }
              showShareChip(clipData);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
          } else if (clipData.getItemAt(0).getUri() != null) {
              if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
                  showShareChip(clipData);
                  accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
              } else {
                  accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
              }
          } else {
              showTextPreview(
                      mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
                      mTextPreview);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
          }
          Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
          // Only show remote copy if it's available.
          PackageManager packageManager = mContext.getPackageManager();
          if (packageManager.resolveActivity(
                  remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
              mRemoteCopyChip.setContentDescription(
                      mContext.getString(R.string.clipboard_send_nearby_description));
              mRemoteCopyChip.setVisibility(View.VISIBLE);
              mRemoteCopyChip.setOnClickListener((v) -> {
                  mUiEventLogger.log(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
                  mContext.startActivity(remoteCopyIntent);
                  animateOut();
              });
              mActionContainerBackground.setVisibility(View.VISIBLE);
          } else {
              mRemoteCopyChip.setVisibility(View.GONE);
          }
          ....         
      }

敏感行为的应用

如果允许用户将敏感内容(例如密码或信用卡信息)复制到剪贴板,则您必须先在 ClipData 中的 ClipDescription 中添加一个标志,然后再调用 ClipboardManager.setPrimaryClip()。

// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
    }
}

// If your app is compiled with a lower SDK.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean("android.content.extra.IS_SENSITIVE", true)
    }
}

具体效果如下:

(设置/未设置)

0条评论
0 / 1000
张****龙
18文章数
0粉丝数
张****龙
18 文章 | 0 粉丝
张****龙
18文章数
0粉丝数
张****龙
18 文章 | 0 粉丝
原创

android13剪切板新增功能

2024-04-29 01:41:31
24
0

剪切板主要框架

官方给出的剪切板主要框架:

 

从 Android 13 开始,将内容添加到剪贴板时,系统会显示标准视觉确认界面。新确认界面会执行以下操作:

  • 确认内容已成功复制。
  • 提供所复制内容的预览。

下面看看实现方式:

新增功能主要流程分析

通过查看搜索,发现剪切板弹框出现在systemuiapp中,源码的位置:
frameworks/base/packages/SystemUI/src/com/android/systemui/clipboardoverlay/
可以看到该目录下存在几个文件:

ClipboardListener.java //用来监听剪切板事件
ClipboardOverlayController.java  //控制UI显示
ClipboardOverlayControllerFactory.java //控制UI显示工厂类
ClipboardOverlayEvent.java //显示消息
EditTextActivity.java //编辑界面

当剪切板变化时候,ClipBoradListener中会监听到剪切板事件,并回调到Listener中的onPrimaryClipChanged事件:

public void onPrimaryClipChanged() {
          if (!mClipboardManager.hasPrimaryClip()) {
              return;
          }
  
          String clipSource = mClipboardManager.getPrimaryClipSource();
          ClipData clipData = mClipboardManager.getPrimaryClip();
  
          if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) {
              Log.i(TAG, "Clipboard overlay suppressed.");
              return;
          }
  
          if (mClipboardOverlayController == null) {
              mClipboardOverlayController = mOverlayFactory.create(mContext);
              mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
          } else {
              mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
          }
          mClipboardOverlayController.setClipData(clipData, clipSource);
          mClipboardOverlayController.setOnSessionCompleteListener(() -> {
              // Session is complete, free memory until it's needed again.
              mClipboardOverlayController = null;
          });
      }

可以看到,对支持Overlay的类型,都会走到ClipboardOverlayController的处理中,这里主要看下setClipData的处理:

 void setClipData(ClipData clipData, String clipSource) {
          ....         
          if (clipData == null || clipData.getItemCount() == 0) {
              showTextPreview(
                      mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
                      mTextPreview);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
          } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
              ClipData.Item item = clipData.getItemAt(0);
              if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                      CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
                  if (item.getTextLinks() != null) {
                      AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
                  }
              }
              if (isSensitive) {
                  showEditableText(
                          mContext.getResources().getString(R.string.clipboard_asterisks), true);
              } else {
                  showEditableText(item.getText(), false);
              }
              showShareChip(clipData);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
          } else if (clipData.getItemAt(0).getUri() != null) {
              if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
                  showShareChip(clipData);
                  accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
              } else {
                  accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
              }
          } else {
              showTextPreview(
                      mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
                      mTextPreview);
              accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
          }
          Intent remoteCopyIntent = getRemoteCopyIntent(clipData);
          // Only show remote copy if it's available.
          PackageManager packageManager = mContext.getPackageManager();
          if (packageManager.resolveActivity(
                  remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
              mRemoteCopyChip.setContentDescription(
                      mContext.getString(R.string.clipboard_send_nearby_description));
              mRemoteCopyChip.setVisibility(View.VISIBLE);
              mRemoteCopyChip.setOnClickListener((v) -> {
                  mUiEventLogger.log(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
                  mContext.startActivity(remoteCopyIntent);
                  animateOut();
              });
              mActionContainerBackground.setVisibility(View.VISIBLE);
          } else {
              mRemoteCopyChip.setVisibility(View.GONE);
          }
          ....         
      }

敏感行为的应用

如果允许用户将敏感内容(例如密码或信用卡信息)复制到剪贴板,则您必须先在 ClipData 中的 ClipDescription 中添加一个标志,然后再调用 ClipboardManager.setPrimaryClip()。

// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
    }
}

// If your app is compiled with a lower SDK.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean("android.content.extra.IS_SENSITIVE", true)
    }
}

具体效果如下:

(设置/未设置)

文章来自个人专栏
linux相关
18 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0