• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { toast } from '../../base/utils/Common';
17import { FileMimeTypeUtil } from '../../base/utils/FileMimeTypeUtil';
18import { FILE_SUFFIX, SELECT_MODE } from '../constants/Constant';
19import ObjectUtil from './ObjectUtil';
20import { ability, Want } from '@kit.AbilityKit';
21import Logger from '../log/Logger';
22import { PickerWindowType } from '../constants/FilePickerItems';
23import { StartModeOptions } from '../model/StartModeOptions';
24import AbilityCommonUtil from './AbilityCommonUtil';
25import { FilesData } from '../../databases/model/FileData';
26
27import ctx from '@ohos.app.ability.common';
28
29export interface abilityResultInterface {
30  want: Want,
31  resultCode: number
32};
33
34export interface PickerStatus {
35  exceedLimit: boolean,
36  differentTypes: boolean
37}
38
39const TAG = 'FilePickerUtil';
40
41export namespace FilePickerUtil {
42  export function returnAbilityResult(want: Want, resultCode: number, options: StartModeOptions) {
43    Logger.i(TAG, 'returnPicker start');
44    let context = getContext() as ctx.UIAbilityContext;
45    if (options.windowType === PickerWindowType.ABILITY) {
46      let abilityResult: abilityResultInterface = {
47        want: want,
48        resultCode: resultCode
49      };
50      Logger.i(TAG, 'terminateSelfWithResult start');
51      context.terminateSelfWithResult(abilityResult, (error) => {
52        Logger.e(TAG, 'terminateSelfWithResult is called = ' + error.code);
53      });
54    } else {
55      let abilityResult: ability.AbilityResult = {
56        resultCode: resultCode,
57        want: want
58      };
59      options.session?.terminateSelfWithResult(abilityResult, (error) => {
60        Logger.e(TAG, 'closeUIExtFilePicker terminateSelfWithResult is called = ' + error?.code);
61      });
62    }
63  }
64
65  export function getStartModeOptions(want: Want): StartModeOptions {
66    let options = new StartModeOptions();
67    if (!want) {
68      Logger.e(TAG, 'getDocumentSelectOptions want is undefined')
69      return options;
70    }
71    options.action = want.action as string || '';
72    options.callerAbilityName = want.parameters?.['ohos.aafwk.param.callerAbilityName'] as string || '';
73    options.callerBundleName = want.parameters?.['ohos.aafwk.param.callerBundleName'] as string || '';
74    options.callerUid = want?.parameters?.[AbilityCommonUtil.CALLER_UID] as number || 0;
75    options.defaultFilePathUri = want.parameters?.key_pick_dir_path as string || '';
76    options.extType = want.parameters?.extType as string || '';
77    options.pickerType = want.parameters?.pickerType as string || '';
78    if (options.isOpenFileMode()) {
79      options.fileSuffixFilters = want.parameters?.key_file_suffix_filter as string[] || [];
80      options.maxSelectNumber = want.parameters?.key_pick_num as number || 1;
81      options.setSelectMode(want.parameters?.key_select_mode as number);
82      options.isAuthMode = want.parameters?.key_auth_mode as boolean || false;
83    } else if (options.isCreateFileMode()) {
84      options.setNewFileNames(want.parameters?.key_pick_file_name as string[]);
85      options.fileSuffixChoices = want.parameters?.key_file_suffix_choices as string[] || [];
86    } else {
87      Logger.e(TAG, 'getDocumentSelectOptions mode is error')
88    }
89    Logger.i(TAG, 'getDocumentOptions : ' + JSON.stringify(options));
90    return options;
91  }
92
93  export function getStartOptionsFromStorage(): StartModeOptions {
94    let storage: LocalStorage = LocalStorage.getShared();
95    if (!storage) {
96      Logger.i(TAG, `Storage is null`)
97      return new StartModeOptions();
98    }
99    let options: StartModeOptions | undefined = storage.get<StartModeOptions>('startModeOptions');
100    if (options === undefined) {
101      options = new StartModeOptions();
102      storage.setOrCreate('startModeOptions', options);
103    }
104    return options;
105  }
106}
107
108/**
109 * 文件选择器文件状态
110 *
111 * @param item 文件对象
112 * @param checkedNum 选中数量
113 * @return 是否超限  选择类型是否不匹配
114 */
115export function pickerStatus(item: FilesData, checkedNum: number, startModeOptions:StartModeOptions): PickerStatus {
116  let status: PickerStatus = {
117    // 选择是否超限
118    exceedLimit: checkedNum >= globalThis.filePickNum && !item.isChecked,
119    // 选择类型是否不匹配
120    differentTypes: !checkFileSelectable(item, startModeOptions)
121  };
122  return status;
123}
124
125/**
126 * 根据文件后缀判断文件是否可选
127 * @param item
128 */
129function checkFileSelectable(item: FilesData, startModeOptions: StartModeOptions): boolean {
130  // selectMode检查
131  let selectMode: number = startModeOptions.selectMode;
132  let isFolder = false;
133  if (ObjectUtil.hasKey(item, 'isFolder')) {
134    isFolder = item.isFolder;
135  }
136  // 文件夹模式,直接返回
137  if (selectMode === SELECT_MODE.FOLDER) {
138    return isFolder;
139  }
140
141  if (isFolder) {
142    // 混选模式下,文件夹直接返回
143    if (selectMode === SELECT_MODE.MIX) {
144      return true;
145    }
146    // 文件模式下,文件夹直接返回false
147    return false;
148  }
149  // 后缀检查
150  let keyFileSuffixFilter: string[] = startModeOptions.fileSuffixFilters;
151  if (Array.isArray(keyFileSuffixFilter) && keyFileSuffixFilter.length > 0) {
152    return checkFileSuffix(item.fileName, keyFileSuffixFilter);
153  }
154
155  // mimeType检查
156  return checkFileMimetype(item.fileName, startModeOptions);
157}
158
159/**
160 * 校验选中的文件后缀
161 *
162 * @param fileName 文件名称
163 * @param keyFileSuffixFilter 指定后缀
164 * @return 如果文件后缀满足三方指定,则返回true
165 */
166function checkFileSuffix(fileName: string, keyFileSuffixFilter: Array<string>): boolean {
167  if (keyFileSuffixFilter) {
168    if (fileName) {
169      const suffix = FILE_SUFFIX.SUFFIX_START + FileMimeTypeUtil.getFileSuffix(fileName);
170      if (keyFileSuffixFilter.includes(suffix)) {
171        return true;
172      }
173    }
174    return false;
175  }
176  return true;
177}
178
179/**
180 * 校验选中的文件mimetype
181 *
182 * @param fileName 文件名称
183 * @return 条件满足返回true
184 */
185function checkFileMimetype(fileName: string, startModeOptions: StartModeOptions): boolean {
186  if (!fileName) {
187    return false;
188  }
189  let keyPickTypeList: string[] = startModeOptions.phonePickerTypeList;
190  // 输入的类型全转换成小写,避免大小敏感问题
191  keyPickTypeList.forEach(item => item.toLowerCase());
192  // 类型列表为空或包含*或*/*时,可选择所有文件
193  if (!keyPickTypeList || keyPickTypeList.length === 0 ||
194  keyPickTypeList.includes('*') || keyPickTypeList.includes('*/*')) {
195    return true;
196  }
197
198  const mimeTypeObj = FileMimeTypeUtil.getFileMimeType(fileName);
199  const mimeType = mimeTypeObj.getMimeType();
200
201  // mimeType未知不可选
202  if (!mimeType) {
203    return false;
204  }
205
206  // mimeType完全匹配
207  if (keyPickTypeList.includes(mimeType)) {
208    return true;
209  }
210
211  let fileCategory = mimeType;
212  const index = mimeType.indexOf('/');
213  if (index > 0) {
214    fileCategory = mimeType.substring(0, index);
215  }
216  // 某一类文件
217  if (keyPickTypeList.includes(fileCategory) || keyPickTypeList.includes(`${fileCategory}/*`)) {
218    return true;
219  }
220
221  return false;
222}
223
224/**
225 * 文件选择器 选择超限提示
226 *
227 * @param isImmersion 是否沉浸式
228 */
229export const filePickerTip = (startModeOptions: StartModeOptions) => {
230  globalThis.abilityContext.resourceManager.getPluralString($r('app.plural.filePickerTip').id,
231    startModeOptions.maxSelectNumber)
232    .then((value: string) => {
233      toast(value)
234    })
235}
236
237
238