OSDN Git Service

Remove unnecessary casts on calls to findViewById
[android-x86/frameworks-base.git] / media / tests / NativeMidiDemo / java / com / example / android / nativemididemo / NativeMidi.java
1 /*
2  * Copyright (C) 2016 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
18 package com.example.android.nativemididemo;
19
20 import android.app.Activity;
21 import android.content.Context;
22 import android.media.midi.MidiDevice;
23 import android.media.midi.MidiDeviceInfo;
24 import android.media.midi.MidiManager;
25 import android.media.midi.MidiOutputPort;
26 import android.media.midi.MidiReceiver;
27 import android.media.AudioManager;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.view.View;
31 import android.view.WindowManager;
32 import android.widget.RadioButton;
33 import android.widget.RadioGroup;
34 import android.widget.TextView;
35
36 import java.io.IOException;
37
38 public class NativeMidi extends Activity
39 {
40     private TextView mCallbackStatusTextView;
41     private TextView mJavaMidiStatusTextView;
42     private TextView mMessagesTextView;
43     private RadioGroup mMidiDevicesRadioGroup;
44     private Handler mTimerHandler = new Handler();
45     private boolean mAudioWorks;
46     private final int mMinFramesPerBuffer = 32;   // See {min|max}PlaySamples in nativemidi-jni.cpp
47     private final int mMaxFramesPerBuffer = 1000;
48     private int mFramesPerBuffer;
49
50     private TouchableScrollView mMessagesContainer;
51     private MidiManager mMidiManager;
52     private MidiOutputPortSelector mActivePortSelector;
53
54     private Runnable mTimerRunnable = new Runnable() {
55         private long mLastTime;
56         private long mLastPlaybackCounter;
57         private int mLastCallbackRate;
58         private long mLastUntouchedTime;
59
60         @Override
61         public void run() {
62             final long checkIntervalMs = 1000;
63             long currentTime = System.currentTimeMillis();
64             long currentPlaybackCounter = getPlaybackCounter();
65             if (currentTime - mLastTime >= checkIntervalMs) {
66                 int callbackRate = Math.round(
67                         (float)(currentPlaybackCounter - mLastPlaybackCounter) /
68                         ((float)(currentTime - mLastTime) / (float)1000));
69                 if (mLastCallbackRate != callbackRate) {
70                     mCallbackStatusTextView.setText(
71                            "CB: " + callbackRate + " Hz");
72                     mLastCallbackRate = callbackRate;
73                 }
74                 mLastTime = currentTime;
75                 mLastPlaybackCounter = currentPlaybackCounter;
76             }
77
78             String[] newMessages = getRecentMessages();
79             if (newMessages != null) {
80                 for (String message : newMessages) {
81                     mMessagesTextView.append(message);
82                     mMessagesTextView.append("\n");
83                 }
84                 if (!mMessagesContainer.isTouched) {
85                     if (mLastUntouchedTime == 0) mLastUntouchedTime = currentTime;
86                     if (currentTime - mLastUntouchedTime > 3000) {
87                         mMessagesContainer.fullScroll(View.FOCUS_DOWN);
88                     }
89                 } else {
90                     mLastUntouchedTime = 0;
91                 }
92             }
93
94             mTimerHandler.postDelayed(this, checkIntervalMs / 4);
95         }
96     };
97
98     private void addMessage(final String message) {
99         mTimerHandler.postDelayed(new Runnable() {
100             @Override
101             public void run() {
102                 mMessagesTextView.append(message);
103             }
104         }, 0);
105     }
106
107     private class MidiOutputPortSelector implements View.OnClickListener {
108         private final MidiDeviceInfo mDeviceInfo;
109         private final int mPortNumber;
110         private MidiDevice mDevice;
111         private MidiOutputPort mOutputPort;
112
113         MidiOutputPortSelector() {
114             mDeviceInfo = null;
115             mPortNumber = -1;
116         }
117
118         MidiOutputPortSelector(MidiDeviceInfo info, int portNumber) {
119             mDeviceInfo = info;
120             mPortNumber = portNumber;
121         }
122
123         MidiDeviceInfo getDeviceInfo() { return mDeviceInfo; }
124
125         @Override
126         public void onClick(View v) {
127             if (mActivePortSelector != null) {
128                 mActivePortSelector.close();
129                 mActivePortSelector = null;
130             }
131             if (mDeviceInfo == null) {
132                 mActivePortSelector = this;
133                 return;
134             }
135             mMidiManager.openDevice(mDeviceInfo, new MidiManager.OnDeviceOpenedListener() {
136                 @Override
137                 public void onDeviceOpened(MidiDevice device) {
138                     if (device == null) {
139                         addMessage("! Failed to open MIDI device !\n");
140                     } else {
141                         mDevice = device;
142                         try {
143                             mDevice.mirrorToNative();
144                             startReadingMidi(mDevice.getInfo().getId(), mPortNumber);
145                         } catch (IOException e) {
146                             addMessage("! Failed to mirror to native !\n" + e.getMessage() + "\n");
147                         }
148
149                         mActivePortSelector = MidiOutputPortSelector.this;
150
151                         mOutputPort = device.openOutputPort(mPortNumber);
152                         mOutputPort.connect(mMidiReceiver);
153                     }
154                 }
155             }, null);
156         }
157
158         void closePortOnly() {
159             stopReadingMidi();
160         }
161
162         void close() {
163             closePortOnly();
164             try {
165                 if (mOutputPort != null) {
166                     mOutputPort.close();
167                 }
168             } catch (IOException e) {
169                 mMessagesTextView.append("! Port close error: " + e + "\n");
170             } finally {
171                 mOutputPort = null;
172             }
173             try {
174                 if (mDevice != null) {
175                     mDevice.close();
176                 }
177             } catch (IOException e) {
178                 mMessagesTextView.append("! Device close error: " + e + "\n");
179             } finally {
180                 mDevice = null;
181             }
182         }
183     }
184
185     private MidiManager.DeviceCallback mMidiDeviceCallback = new MidiManager.DeviceCallback() {
186         @Override
187         public void onDeviceAdded(MidiDeviceInfo info) {
188             Bundle deviceProps = info.getProperties();
189             String deviceName = deviceProps.getString(MidiDeviceInfo.PROPERTY_NAME);
190             if (deviceName == null) {
191                 deviceName = deviceProps.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);
192             }
193
194             for (MidiDeviceInfo.PortInfo port : info.getPorts()) {
195                 if (port.getType() != MidiDeviceInfo.PortInfo.TYPE_OUTPUT) continue;
196                 String portName = port.getName();
197                 int portNumber = port.getPortNumber();
198                 if (portName.length() == 0) portName = "[" + portNumber + "]";
199                 portName += "@" + deviceName;
200                 RadioButton outputDevice = new RadioButton(NativeMidi.this);
201                 outputDevice.setText(portName);
202                 outputDevice.setTag(info);
203                 outputDevice.setOnClickListener(new MidiOutputPortSelector(info, portNumber));
204                 mMidiDevicesRadioGroup.addView(outputDevice);
205             }
206
207             NativeMidi.this.updateKeepScreenOn();
208         }
209
210         @Override
211         public void onDeviceRemoved(MidiDeviceInfo info) {
212             if (mActivePortSelector != null && info.equals(mActivePortSelector.getDeviceInfo())) {
213                 mActivePortSelector.close();
214                 mActivePortSelector = null;
215             }
216             int removeButtonStart = -1, removeButtonCount = 0;
217             final int buttonCount = mMidiDevicesRadioGroup.getChildCount();
218             boolean checked = false;
219             for (int i = 0; i < buttonCount; ++i) {
220                 RadioButton button = (RadioButton) mMidiDevicesRadioGroup.getChildAt(i);
221                 if (!info.equals(button.getTag())) continue;
222                 if (removeButtonStart == -1) removeButtonStart = i;
223                 ++removeButtonCount;
224                 if (button.isChecked()) checked = true;
225             }
226             if (removeButtonStart != -1) {
227                 mMidiDevicesRadioGroup.removeViews(removeButtonStart, removeButtonCount);
228                 if (checked) {
229                     mMidiDevicesRadioGroup.check(R.id.device_none);
230                 }
231             }
232
233             NativeMidi.this.updateKeepScreenOn();
234         }
235     };
236
237     private class JavaMidiReceiver extends MidiReceiver implements Runnable {
238         @Override
239         public void onSend(byte[] data, int offset,
240                 int count, long timestamp) throws IOException {
241             mTimerHandler.removeCallbacks(this);
242             mTimerHandler.postDelayed(new Runnable() {
243                 @Override
244                 public void run() {
245                     mJavaMidiStatusTextView.setText("Java: MSG");
246                 }
247             }, 0);
248             mTimerHandler.postDelayed(this, 100);
249         }
250
251         @Override
252         public void run() {
253             mJavaMidiStatusTextView.setText("Java: ---");
254         }
255     }
256
257     private JavaMidiReceiver mMidiReceiver = new JavaMidiReceiver();
258
259     private void updateKeepScreenOn() {
260         if (mMidiDevicesRadioGroup.getChildCount() > 1) {
261             getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
262         } else {
263             getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
264         }
265     }
266
267     @Override
268     public void onCreate(Bundle savedInstanceState) {
269         super.onCreate(savedInstanceState);
270         setContentView(R.layout.main);
271
272         mCallbackStatusTextView = findViewById(R.id.callback_status);
273         mJavaMidiStatusTextView = findViewById(R.id.java_midi_status);
274         mMessagesTextView = findViewById(R.id.messages);
275         mMessagesContainer = findViewById(R.id.messages_scroll);
276         mMidiDevicesRadioGroup = findViewById(R.id.devices);
277         RadioButton deviceNone = findViewById(R.id.device_none);
278         deviceNone.setOnClickListener(new MidiOutputPortSelector());
279
280         AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
281         String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
282         if (sampleRate == null) sampleRate = "48000";
283         String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
284         if (framesPerBuffer == null) framesPerBuffer = Integer.toString(mMaxFramesPerBuffer);
285         mFramesPerBuffer = Integer.parseInt(framesPerBuffer);
286         String audioInitResult = initAudio(Integer.parseInt(sampleRate), mFramesPerBuffer);
287         mMessagesTextView.append("Open SL ES init: " + audioInitResult + "\n");
288
289         if (audioInitResult.startsWith("Success")) {
290             mAudioWorks = true;
291             mTimerHandler.postDelayed(mTimerRunnable, 0);
292             mTimerHandler.postDelayed(mMidiReceiver, 0);
293         }
294
295         mMidiManager = (MidiManager) getSystemService(Context.MIDI_SERVICE);
296         mMidiManager.registerDeviceCallback(mMidiDeviceCallback, new Handler());
297         for (MidiDeviceInfo info : mMidiManager.getDevices()) {
298             mMidiDeviceCallback.onDeviceAdded(info);
299         }
300     }
301
302     @Override
303     public void onPause() {
304         super.onPause();
305         if (mAudioWorks) {
306             mTimerHandler.removeCallbacks(mTimerRunnable);
307             pauseAudio();
308         }
309     }
310
311     @Override
312     public void onResume() {
313         super.onResume();
314         if (mAudioWorks) {
315             mTimerHandler.postDelayed(mTimerRunnable, 0);
316             resumeAudio();
317         }
318     }
319
320     @Override
321     protected void onDestroy() {
322         if (mActivePortSelector != null) {
323             mActivePortSelector.close();
324             mActivePortSelector = null;
325         }
326         shutdownAudio();
327         super.onDestroy();
328     }
329
330     public void onClearMessages(View v) {
331         mMessagesTextView.setText("");
332     }
333
334     public void onClosePort(View v) {
335         if (mActivePortSelector != null) {
336             mActivePortSelector.closePortOnly();
337         }
338     }
339
340     private native String initAudio(int sampleRate, int playSamples);
341     private native void pauseAudio();
342     private native void resumeAudio();
343     private native void shutdownAudio();
344
345     private native long getPlaybackCounter();
346     private native String[] getRecentMessages();
347
348     private native void startReadingMidi(int deviceId, int portNumber);
349     private native void stopReadingMidi();
350
351     static {
352         System.loadLibrary("nativemidi_jni");
353     }
354 }