1/*
2 * Copyright (c) 2021-2022 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 AccountManager from "@ohos.account.osAccount";
17import {Log} from "./Log";
18import {createOrGet} from "./SingleInstanceHelper";
19
20const TAG = "SwitchUserManagerSc";
21const SUBSCRIBE_KEY = "SystemUiAccount";
22const USER_CHANGE_EVENT = "activate";
23const DELAY_TIME = 50 * 1000;
24export const INVALID_USER_ID = -1;
25
26type AccountInfo = {
27  localId: number;
28  localName: string;
29  photo: string;
30};
31export type UserChangeListener = {
32  userChange: (data: UserInfo) => void;
33};
34
35export class UserInfo {
36  userId: number = INVALID_USER_ID;
37  userName: string = "";
38  userIcon: string | Resource = "";
39  [key: string]: any;
40}
41
42async function getCurrentAccountInfo(): Promise<AccountInfo> {
43  let accountInfos = await AccountManager.getAccountManager().queryAllCreatedOsAccounts();
44  Log.showInfo(TAG, `accountInfos size:${accountInfos.length}`);
45  for (let accountInfo of accountInfos) {
46    Log.showDebug(TAG, `accountInfo: ${accountInfo.localId}, isActive: ${accountInfo.isActived}`);
47    if (accountInfo.isActived) {
48      return accountInfo;
49    }
50  }
51  return Promise.reject("Can't get active userInfo.");
52}
53
54function parseAccountInfo(accountInfo: AccountInfo): UserInfo {
55  return {
56    userId: accountInfo.localId,
57    userName: accountInfo.localName,
58    userIcon: accountInfo.photo,
59  };
60}
61
62export class SwitchUserManager {
63  mUserInfo: UserInfo = new UserInfo();
64  mListeners = new Set<UserChangeListener>();
65  mHasWait: boolean = false;
66
67  static getInstance(): SwitchUserManager {
68    return createOrGet(SwitchUserManager, TAG);
69  }
70
71  constructor() {
72    Log.showDebug(TAG, `SwitchUserManager constructor`);
73    AccountManager.getAccountManager().on(USER_CHANGE_EVENT, SUBSCRIBE_KEY, this.handleUserChange.bind(this));
74  }
75
76  public async getCurrentUserInfo(): Promise<UserInfo> {
77    if (this.mUserInfo.userId == INVALID_USER_ID) {
78      !this.mHasWait && (await new Promise((resolve) => setTimeout(resolve, DELAY_TIME)));
79      this.mHasWait = true;
80      this.mUserInfo = parseAccountInfo(await getCurrentAccountInfo());
81    }
82    Log.showInfo(TAG, `getCurrentUserInfo userId: ${this.mUserInfo.userId}`);
83    return this.mUserInfo;
84  }
85
86  public registerListener(listener: UserChangeListener) {
87    this.mListeners.add(listener);
88  }
89
90  public unregisterListener(listener: UserChangeListener) {
91    this.mListeners.delete(listener);
92  }
93
94  handleUserChange(accountId: number): void {
95    AccountManager.getAccountManager()
96      .queryOsAccountById(accountId)
97      .then((accountInfo) => {
98        Log.showInfo(TAG, `userChange, accountInfo: ${JSON.stringify(accountInfo)}`);
99        this.mUserInfo = parseAccountInfo(accountInfo);
100        this.notifyUserChange();
101      })
102      .catch((err) => Log.showError(TAG, `Can't query account by ${accountId}, err: ${err}`));
103  }
104
105  notifyUserChange() {
106    this.mListeners.forEach((listener) => listener.userChange(this.mUserInfo));
107  }
108}