1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.systemui.analytics;
18 
19 import android.os.Build;
20 import android.util.Log;
21 import android.view.MotionEvent;
22 
23 import java.util.ArrayList;
24 
25 import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session;
26 import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.PhoneEvent;
27 import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.SensorEvent;
28 import static com.android.systemui.statusbar.phone.nano.TouchAnalyticsProto.Session.TouchEvent;
29 
30 /**
31  * Collects touch, sensor and phone events and converts the data to
32  * TouchAnalyticsProto.Session.
33  */
34 public class SensorLoggerSession {
35     private static final String TAG = "SensorLoggerSession";
36 
37     private final long mStartTimestampMillis;
38     private final long mStartSystemTimeNanos;
39 
40     private long mEndTimestampMillis;
41     private int mType;
42 
43     private ArrayList<TouchEvent> mMotionEvents = new ArrayList<>();
44     private ArrayList<SensorEvent> mSensorEvents = new ArrayList<>();
45     private ArrayList<PhoneEvent> mPhoneEvents = new ArrayList<>();
46     private int mTouchAreaHeight;
47     private int mTouchAreaWidth;
48     private int mResult = Session.UNKNOWN;
49 
SensorLoggerSession(long startTimestampMillis, long startSystemTimeNanos)50     public SensorLoggerSession(long startTimestampMillis, long startSystemTimeNanos) {
51         mStartTimestampMillis = startTimestampMillis;
52         mStartSystemTimeNanos = startSystemTimeNanos;
53         mType = Session.REAL;
54     }
55 
setType(int type)56     public void setType(int type) {
57         mType = type;
58     }
59 
end(long endTimestampMillis, int result)60     public void end(long endTimestampMillis, int result) {
61         mResult = result;
62         mEndTimestampMillis = endTimestampMillis;
63 
64         if (DataCollector.DEBUG) {
65             Log.d(TAG, "Ending session result=" + result + " it lasted for " +
66                     (float) (mEndTimestampMillis - mStartTimestampMillis) / 1000f + "s");
67         }
68     }
69 
addMotionEvent(MotionEvent motionEvent)70     public void addMotionEvent(MotionEvent motionEvent) {
71         TouchEvent event = motionEventToProto(motionEvent);
72         mMotionEvents.add(event);
73     }
74 
addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos)75     public void addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos) {
76         SensorEvent event = sensorEventToProto(eventOrig, systemTimeNanos);
77         mSensorEvents.add(event);
78     }
79 
addPhoneEvent(int eventType, long systemTimeNanos)80     public void addPhoneEvent(int eventType, long systemTimeNanos) {
81         PhoneEvent event = phoneEventToProto(eventType, systemTimeNanos);
82         mPhoneEvents.add(event);
83     }
84 
85 
86     @Override
toString()87     public String toString() {
88         final StringBuilder sb = new StringBuilder("Session{");
89         sb.append("mStartTimestampMillis=").append(mStartTimestampMillis);
90         sb.append(", mStartSystemTimeNanos=").append(mStartSystemTimeNanos);
91         sb.append(", mEndTimestampMillis=").append(mEndTimestampMillis);
92         sb.append(", mResult=").append(mResult);
93         sb.append(", mTouchAreaHeight=").append(mTouchAreaHeight);
94         sb.append(", mTouchAreaWidth=").append(mTouchAreaWidth);
95         sb.append(", mMotionEvents=[size=").append(mMotionEvents.size()).append("]");
96         sb.append(", mSensorEvents=[size=").append(mSensorEvents.size()).append("]");
97         sb.append(", mPhoneEvents=[size=").append(mPhoneEvents.size()).append("]");
98         sb.append('}');
99         return sb.toString();
100     }
101 
toProto()102     public Session toProto() {
103         Session proto = new Session();
104         proto.setStartTimestampMillis(mStartTimestampMillis);
105         proto.setDurationMillis(mEndTimestampMillis - mStartTimestampMillis);
106         proto.setBuild(Build.FINGERPRINT);
107         proto.setResult(mResult);
108         proto.setType(mType);
109         proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
110         proto.touchEvents = mMotionEvents.toArray(proto.touchEvents);
111         proto.phoneEvents = mPhoneEvents.toArray(proto.phoneEvents);
112         proto.setTouchAreaWidth(mTouchAreaWidth);
113         proto.setTouchAreaHeight(mTouchAreaHeight);
114         return proto;
115     }
116 
phoneEventToProto(int eventType, long sysTimeNanos)117     private PhoneEvent phoneEventToProto(int eventType, long sysTimeNanos) {
118         PhoneEvent proto = new PhoneEvent();
119         proto.setType(eventType);
120         proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
121         return proto;
122     }
123 
sensorEventToProto(android.hardware.SensorEvent ev, long sysTimeNanos)124     private SensorEvent sensorEventToProto(android.hardware.SensorEvent ev, long sysTimeNanos) {
125         SensorEvent proto = new SensorEvent();
126         proto.setType(ev.sensor.getType());
127         proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
128         proto.setTimestamp(ev.timestamp);
129         proto.values = ev.values.clone();
130         return proto;
131     }
132 
motionEventToProto(MotionEvent ev)133     private TouchEvent motionEventToProto(MotionEvent ev) {
134         int count = ev.getPointerCount();
135         TouchEvent proto = new TouchEvent();
136         proto.setTimeOffsetNanos(ev.getEventTimeNano() - mStartSystemTimeNanos);
137         proto.setAction(ev.getActionMasked());
138         proto.setActionIndex(ev.getActionIndex());
139         proto.pointers = new TouchEvent.Pointer[count];
140         for (int i = 0; i < count; i++) {
141             TouchEvent.Pointer p = new TouchEvent.Pointer();
142             p.setX(ev.getX(i));
143             p.setY(ev.getY(i));
144             p.setSize(ev.getSize(i));
145             p.setPressure(ev.getPressure(i));
146             p.setId(ev.getPointerId(i));
147             proto.pointers[i] = p;
148         }
149         return proto;
150     }
151 
setTouchArea(int width, int height)152     public void setTouchArea(int width, int height) {
153         mTouchAreaWidth = width;
154         mTouchAreaHeight = height;
155     }
156 
getResult()157     public int getResult() {
158         return mResult;
159     }
160 
getStartTimestampMillis()161     public long getStartTimestampMillis() {
162         return mStartTimestampMillis;
163     }
164 }
165