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.example.android.midiscope;
18 
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.media.midi.MidiDeviceInfo;
22 import android.media.midi.MidiManager;
23 import android.media.midi.MidiReceiver;
24 import android.os.Bundle;
25 import android.view.Menu;
26 import android.view.MenuItem;
27 import android.view.View;
28 import android.view.WindowManager;
29 import android.widget.ScrollView;
30 import android.widget.TextView;
31 import android.widget.Toolbar;
32 
33 import com.example.android.common.midi.MidiFramer;
34 import com.example.android.common.midi.MidiOutputPortSelector;
35 import com.example.android.common.midi.MidiPortWrapper;
36 
37 import java.util.LinkedList;
38 
39 /**
40  * App that provides a MIDI echo service.
41  */
42 public class MainActivity extends Activity implements ScopeLogger {
43 
44     private static final int MAX_LINES = 100;
45 
46     private final LinkedList<String> mLogLines = new LinkedList<>();
47     private TextView mLog;
48     private ScrollView mScroller;
49     private MidiOutputPortSelector mLogSenderSelector;
50 
51     @Override
onCreate(Bundle savedInstanceState)52     public void onCreate(Bundle savedInstanceState) {
53         super.onCreate(savedInstanceState);
54         setContentView(R.layout.main);
55 
56         setActionBar((Toolbar) findViewById(R.id.toolbar));
57         ActionBar actionBar = getActionBar();
58         if (actionBar != null) {
59             actionBar.setDisplayShowTitleEnabled(false);
60         }
61 
62         mLog = (TextView) findViewById(R.id.log);
63         mScroller = (ScrollView) findViewById(R.id.scroll);
64 
65         // Setup MIDI
66         MidiManager midiManager = (MidiManager) getSystemService(MIDI_SERVICE);
67 
68         // Receiver that prints the messages.
69         MidiReceiver loggingReceiver = new LoggingReceiver(this);
70 
71         // Receiver that parses raw data into complete messages.
72         MidiFramer connectFramer = new MidiFramer(loggingReceiver);
73 
74         // Setup a menu to select an input source.
75         mLogSenderSelector = new MidiOutputPortSelector(midiManager, this, R.id.spinner_senders) {
76             @Override
77             public void onPortSelected(final MidiPortWrapper wrapper) {
78                 super.onPortSelected(wrapper);
79                 if (wrapper != null) {
80                     mLogLines.clear();
81                     MidiDeviceInfo deviceInfo = wrapper.getDeviceInfo();
82                     if (deviceInfo == null) {
83                         log(getString(R.string.header_text));
84                     } else {
85                         log(MidiPrinter.formatDeviceInfo(deviceInfo));
86                     }
87                 }
88             }
89         };
90         mLogSenderSelector.getSender().connect(connectFramer);
91 
92         // Tell the virtual device to log its messages here..
93         MidiScope.setScopeLogger(this);
94     }
95 
96     @Override
onDestroy()97     public void onDestroy() {
98         mLogSenderSelector.onClose();
99         // The scope will live on as a service so we need to tell it to stop
100         // writing log messages to this Activity.
101         MidiScope.setScopeLogger(null);
102         super.onDestroy();
103     }
104 
105     @Override
onCreateOptionsMenu(Menu menu)106     public boolean onCreateOptionsMenu(Menu menu) {
107         getMenuInflater().inflate(R.menu.main, menu);
108         setKeepScreenOn(menu.findItem(R.id.action_keep_screen_on).isChecked());
109         return true;
110     }
111 
112     @Override
onOptionsItemSelected(MenuItem item)113     public boolean onOptionsItemSelected(MenuItem item) {
114         switch (item.getItemId()) {
115             case R.id.action_clear_all:
116                 mLogLines.clear();
117                 logOnUiThread("");
118                 break;
119             case R.id.action_keep_screen_on:
120                 boolean checked = !item.isChecked();
121                 setKeepScreenOn(checked);
122                 item.setChecked(checked);
123                 break;
124         }
125         return super.onOptionsItemSelected(item);
126     }
127 
setKeepScreenOn(boolean keepScreenOn)128     private void setKeepScreenOn(boolean keepScreenOn) {
129         if (keepScreenOn) {
130             getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
131         } else {
132             getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
133         }
134     }
135 
136     @Override
log(final String string)137     public void log(final String string) {
138         runOnUiThread(new Runnable() {
139             @Override
140             public void run() {
141                 logOnUiThread(string);
142             }
143         });
144     }
145 
146     /**
147      * Logs a message to our TextView. This needs to be called from the UI thread.
148      */
logOnUiThread(String s)149     private void logOnUiThread(String s) {
150         mLogLines.add(s);
151         if (mLogLines.size() > MAX_LINES) {
152             mLogLines.removeFirst();
153         }
154         // Render line buffer to one String.
155         StringBuilder sb = new StringBuilder();
156         for (String line : mLogLines) {
157             sb.append(line).append('\n');
158         }
159         mLog.setText(sb.toString());
160         mScroller.fullScroll(View.FOCUS_DOWN);
161     }
162 }
163