1e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer/*
2e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Copyright (C) 2016 The Android Open Source Project
3e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
4e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Licensed under the Apache License, Version 2.0 (the "License");
5e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * you may not use this file except in compliance with the License.
6e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * You may obtain a copy of the License at
7e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
8e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *      http://www.apache.org/licenses/LICENSE-2.0
9e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer *
10e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * Unless required by applicable law or agreed to in writing, software
11e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * distributed under the License is distributed on an "AS IS" BASIS,
12e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * See the License for the specific language governing permissions and
14e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer * limitations under the License.
15e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer */
16e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
17e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerpackage org.chromium.latency.walt;
18e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
19e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.content.BroadcastReceiver;
20e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.content.Context;
21e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.content.Intent;
22e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.os.Bundle;
23e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.support.v4.app.Fragment;
24e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.text.method.ScrollingMovementMethod;
25e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.view.LayoutInflater;
26e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.view.View;
27e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.view.ViewGroup;
28e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport android.widget.TextView;
29e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
30e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerimport java.util.Locale;
31e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
32e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmerpublic class MidiFragment extends Fragment
33e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        implements View.OnClickListener, BaseTest.TestStateListener {
34e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
35e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private SimpleLogger logger;
36e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private TextView textView;
37e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private View startMidiInButton;
38e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private View startMidiOutButton;
39e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private HistogramChart latencyChart;
40e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private MidiTest midiTest;
41e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
42e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public MidiFragment() {
43e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // Required empty public constructor
44e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
45e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
46e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
47e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public View onCreateView(LayoutInflater inflater, ViewGroup container,
48e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                             Bundle savedInstanceState) {
49e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        logger = SimpleLogger.getInstance(getContext());
50e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        midiTest = new MidiTest(getActivity());
51e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        midiTest.setTestStateListener(this);
52e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
53e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        final View view = inflater.inflate(R.layout.fragment_midi, container, false);
54e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        textView = (TextView) view.findViewById(R.id.txt_box_midi);
55e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiInButton = view.findViewById(R.id.button_start_midi_in);
56e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiOutButton = view.findViewById(R.id.button_start_midi_out);
57e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        latencyChart = (HistogramChart) view.findViewById(R.id.latency_chart);
58e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        textView.setMovementMethod(new ScrollingMovementMethod());
59e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return view;
60e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
61e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
62e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
63e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onResume() {
64e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        super.onResume();
65e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
66e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        // Register this fragment class as the listener for some button clicks
67e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiInButton.setOnClickListener(this);
68e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiOutButton.setOnClickListener(this);
69e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
70e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        textView.setText(logger.getLogText());
71e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        logger.registerReceiver(logReceiver);
72e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
73e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
74e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
75e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onPause() {
76e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        logger.unregisterReceiver(logReceiver);
77e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        super.onPause();
78e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
79e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
80e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
81e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onClick(View v) {
82e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        switch (v.getId()) {
83e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case R.id.button_start_midi_in:
84e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                disableButtons();
85e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.setVisibility(View.VISIBLE);
86e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.clearData();
87e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.setLegendEnabled(false);
88e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.getBarChart().getDescription().setText("MIDI Input Latency [ms]");
89e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                midiTest.testMidiIn();
90e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                break;
91e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            case R.id.button_start_midi_out:
92e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                disableButtons();
93e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.setVisibility(View.VISIBLE);
94e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.clearData();
95e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.setLegendEnabled(false);
96e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                latencyChart.getBarChart().getDescription().setText("MIDI Output Latency [ms]");
97e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                midiTest.testMidiOut();
98e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                break;
99e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
100e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
101e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
102e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private void disableButtons() {
103e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiInButton.setEnabled(false);
104e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiOutButton.setEnabled(false);
105e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
106e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
107e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    private BroadcastReceiver logReceiver = new BroadcastReceiver() {
108e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        @Override
109e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        public void onReceive(Context context, Intent intent) {
110e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            String msg = intent.getStringExtra("message");
111e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            textView.append(msg + "\n");
112e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
113e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    };
114e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
115e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
116e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onTestStopped() {
117e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        if (!midiTest.deltasOutputTotal.isEmpty()) {
118e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            latencyChart.setLegendEnabled(true);
119e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            latencyChart.setLabel(String.format(
120e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                    Locale.US, "Median=%.1f ms", Utils.median(midiTest.deltasOutputTotal)));
121e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        } else if (!midiTest.deltasInputTotal.isEmpty()) {
122e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            latencyChart.setLegendEnabled(true);
123e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer            latencyChart.setLabel(String.format(
124e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                    Locale.US, "Median=%.1f ms", Utils.median(midiTest.deltasInputTotal)));
125e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        }
126e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        LogUploader.uploadIfAutoEnabled(getContext());
127e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiInButton.setEnabled(true);
128e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        startMidiOutButton.setEnabled(true);
129e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
130e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
131e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
132e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onTestStoppedWithError() {
133e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        onTestStopped();
134e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        latencyChart.setVisibility(View.GONE);
135e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
136e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
137e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    @Override
138e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public void onTestPartialResult(double value) {
139e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        latencyChart.addEntry(value);
140e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
141e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer
142e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    public static boolean hasMidi(Context context) {
143e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer        return context.getPackageManager().
144e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer                hasSystemFeature("android.software.midi");
145e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer    }
146e76dcf96b0c451e46cddfa695de8feeb92533937Andrew Lehmer}
147