13516800b611a79339a3c188332d13a26e9086b09Adam Lesinski/**
23516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Copyright (C) 2014 The Android Open Source Project
33516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
43516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not
53516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * use this file except in compliance with the License. You may obtain a copy
63516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * of the License at
73516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
83516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0
93516800b611a79339a3c188332d13a26e9086b09Adam Lesinski *
103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * Unless required by applicable law or agreed to in writing, software
113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
123516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
133516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * License for the specific language governing permissions and limitations
143516800b611a79339a3c188332d13a26e9086b09Adam Lesinski * under the License.
153516800b611a79339a3c188332d13a26e9086b09Adam Lesinski */
163516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipackage com.android.tests.usagestats;
173516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
183516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.ListActivity;
193516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageEvents;
203516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.app.usage.UsageStatsManager;
213516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.content.Context;
223516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.os.Bundle;
233516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.os.Handler;
247f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinskiimport android.support.v4.util.CircularArray;
253516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.view.LayoutInflater;
263516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.view.View;
273516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.view.ViewGroup;
283516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.widget.BaseAdapter;
293516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport android.widget.TextView;
303516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
313516800b611a79339a3c188332d13a26e9086b09Adam Lesinskiimport java.util.ArrayList;
323516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
333516800b611a79339a3c188332d13a26e9086b09Adam Lesinskipublic class UsageLogActivity extends ListActivity implements Runnable {
343516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
353516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
363516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private UsageStatsManager mUsageStatsManager;
373516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private Adapter mAdapter;
383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private Handler mHandler = new Handler();
397f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski    private long mLastTime;
403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    @Override
423516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    protected void onCreate(Bundle savedInstanceState) {
433516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        super.onCreate(savedInstanceState);
443516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        mLastTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
473516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        mAdapter = new Adapter();
483516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        setListAdapter(mAdapter);
493516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
503516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
513516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    @Override
523516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    protected void onResume() {
533516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        super.onResume();
543516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        run();
553516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
563516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
573516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    @Override
583516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    protected void onPause() {
593516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        super.onPause();
603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        mHandler.removeCallbacks(this);
613516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    @Override
643516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    public void run() {
653516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        long now = System.currentTimeMillis();
667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        UsageEvents events = mUsageStatsManager.queryEvents(mLastTime, now);
677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        long lastEventTime = mAdapter.update(events);
687f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        if (lastEventTime >= 0) {
697f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            mLastTime = lastEventTime + 1;
707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        mHandler.postDelayed(this, 1000 * 5);
723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    private class Adapter extends BaseAdapter {
757f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        private static final int MAX_EVENTS = 50;
767f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        private final CircularArray<UsageEvents.Event> mEvents = new CircularArray<>(MAX_EVENTS);
773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        public long update(UsageEvents results) {
797f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            long lastTimeStamp = -1;
803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            while (results.hasNextEvent()) {
813516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                UsageEvents.Event event = new UsageEvents.Event();
823516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                results.getNextEvent(event);
837f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                lastTimeStamp = event.getTimeStamp();
847f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                if (mEvents.size() == MAX_EVENTS) {
857f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    mEvents.popLast();
867f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                }
877f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                mEvents.addFirst(event);
883516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
8966143fa5b34eea7413335111838fb692987b611aAdam Lesinski
9066143fa5b34eea7413335111838fb692987b611aAdam Lesinski            if (lastTimeStamp != 0) {
9166143fa5b34eea7413335111838fb692987b611aAdam Lesinski                notifyDataSetChanged();
9266143fa5b34eea7413335111838fb692987b611aAdam Lesinski            }
937f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            return lastTimeStamp;
943516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
953516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
963516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        @Override
973516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        public int getCount() {
983516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            return mEvents.size();
993516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1003516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1013516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        @Override
1027f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        public UsageEvents.Event getItem(int position) {
1033516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            return mEvents.get(position);
1043516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1053516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1063516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        @Override
1073516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        public long getItemId(int position) {
1083516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            return position;
1093516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1103516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1113516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        @Override
1127f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        public int getItemViewType(int position) {
1137f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            final int eventType = getItem(position).getEventType();
1147f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (eventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
1157f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                return 1;
1167f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
1177f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            return 0;
1187f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1197f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1207f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        @Override
1213516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        public View getView(int position, View convertView, ViewGroup parent) {
1227f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            final UsageEvents.Event event = getItem(position);
1237f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1243516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            final ViewHolder holder;
1253516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            if (convertView == null) {
1263516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                holder = new ViewHolder();
1277f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1287f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                if (event.getEventType() == UsageEvents.Event.CONFIGURATION_CHANGE) {
1297f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    convertView = LayoutInflater.from(UsageLogActivity.this)
1307f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                            .inflate(R.layout.config_row_item, parent, false);
1317f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    holder.config = (TextView) convertView.findViewById(android.R.id.text1);
1327f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                } else {
1337f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    convertView = LayoutInflater.from(UsageLogActivity.this)
1347f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                            .inflate(R.layout.row_item, parent, false);
1357f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    holder.packageName = (TextView) convertView.findViewById(android.R.id.text1);
1367f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    holder.state = (TextView) convertView.findViewById(android.R.id.text2);
1377f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                }
1383516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                convertView.setTag(holder);
1393516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            } else {
1403516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                holder = (ViewHolder) convertView.getTag();
1413516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
1423516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1437f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (holder.packageName != null) {
1447f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                holder.packageName.setText(event.getPackageName());
1457f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
1467f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1477f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (holder.state != null) {
1487f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                holder.state.setText(eventToString(event.getEventType()));
1497f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
1507f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1517f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            if (holder.config != null &&
1527f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    event.getEventType() == UsageEvents.Event.CONFIGURATION_CHANGE) {
1537f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                holder.config.setText(event.getConfiguration().toString());
1547f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            }
1557f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            return convertView;
1567f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        }
1577f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1587f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        private String eventToString(int eventType) {
1597f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski            switch (eventType) {
1603516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                case UsageEvents.Event.MOVE_TO_FOREGROUND:
1617f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    return "Foreground";
1623516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1633516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                case UsageEvents.Event.MOVE_TO_BACKGROUND:
1647f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    return "Background";
1657f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski
1667f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                case UsageEvents.Event.CONFIGURATION_CHANGE:
1677f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    return "Config change";
1683516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1693516800b611a79339a3c188332d13a26e9086b09Adam Lesinski                default:
1707f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski                    return "Unknown: " + eventType;
1713516800b611a79339a3c188332d13a26e9086b09Adam Lesinski            }
1723516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        }
1733516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1743516800b611a79339a3c188332d13a26e9086b09Adam Lesinski
1753516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    static class ViewHolder {
1763516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        public TextView packageName;
1773516800b611a79339a3c188332d13a26e9086b09Adam Lesinski        public TextView state;
1787f61e96db7c90c1f4418359672aa4656aebee500Adam Lesinski        public TextView config;
1793516800b611a79339a3c188332d13a26e9086b09Adam Lesinski    }
1803516800b611a79339a3c188332d13a26e9086b09Adam Lesinski}
181