/* * Copyright (C) 2017 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 com.android.systemui.statusbar.policy; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.STATUS_BAR_ICONS_CHANGED; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION; import android.content.Context; import android.metrics.LogMaker; import android.os.Handler; import android.os.Looper; import android.support.annotation.VisibleForTesting; import android.util.ArraySet; import com.android.internal.logging.MetricsLogger; import java.util.Arrays; import java.util.List; public class IconLoggerImpl implements IconLogger { // Minimum ms between log statements. // NonFinalForTesting @VisibleForTesting protected static long MIN_LOG_INTERVAL = 1000; private final Context mContext; private final Handler mHandler; private final MetricsLogger mLogger; private final ArraySet mIcons = new ArraySet<>(); private final List mIconIndex; private long mLastLog = System.currentTimeMillis(); public IconLoggerImpl(Context context, Looper bgLooper, MetricsLogger logger) { mContext = context; mHandler = new Handler(bgLooper); mLogger = logger; String[] icons = mContext.getResources().getStringArray( com.android.internal.R.array.config_statusBarIcons); mIconIndex = Arrays.asList(icons); doLog(); } @Override public void onIconShown(String tag) { synchronized (mIcons) { if (mIcons.contains(tag)) return; mIcons.add(tag); } if (!mHandler.hasCallbacks(mLog)) { mHandler.postDelayed(mLog, MIN_LOG_INTERVAL); } } @Override public void onIconHidden(String tag) { synchronized (mIcons) { if (!mIcons.contains(tag)) return; mIcons.remove(tag); } if (!mHandler.hasCallbacks(mLog)) { mHandler.postDelayed(mLog, MIN_LOG_INTERVAL); } } private void doLog() { long time = System.currentTimeMillis(); long timeSinceLastLog = time - mLastLog; mLastLog = time; ArraySet icons; synchronized (mIcons) { icons = new ArraySet<>(mIcons); } mLogger.write(new LogMaker(STATUS_BAR_ICONS_CHANGED) .setType(TYPE_ACTION) .setLatency(timeSinceLastLog) .addTaggedData(FIELD_NUM_STATUS_ICONS, icons.size()) .addTaggedData(FIELD_STATUS_ICONS, getBitField(icons))); } private int getBitField(ArraySet icons) { int iconsVisible = 0; for (String icon : icons) { int index = mIconIndex.indexOf(icon); if (index >= 0) { iconsVisible |= (1 << index); } } return iconsVisible; } private final Runnable mLog = this::doLog; }