Java tutorial
package com.dosse.bwentrain.androidPlayer; import android.app.Notification; import android.app.PendingIntent; import android.content.ContentResolver; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.view.Menu; import android.view.MenuItem; import com.dosse.bwentrain.core.Envelope; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; import com.dosse.bwentrain.core.Preset; import com.dosse.bwentrain.renderers.isochronic.IsochronicRenderer; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdSize; import com.google.android.gms.ads.AdView; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import android.support.v7.app.ActionBarActivity; import android.support.v4.app.Fragment; import android.app.AlertDialog; import android.app.NotificationManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.Settings.Secure; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.ProgressBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.SimpleAdapter; import android.widget.Toast; import android.widget.TextView; import android.widget.SeekBar; import android.widget.Button; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private static PlayerController pc; //PlayerController interfaces with LibBWEntrainment to control the playback static { new IsochronicRenderer(null, null, 0).stopPlaying(); } //preload IsochronicRenderer private Menu optionsMenu; //pointer to optionsMenu, used by AdsController to remove purchase option if app is licensed private int adsH; /** * checks license and loads ads if needed. * also, great example of overhead: 70% of the code is there only because android wants it * I also apologize for all the try-catches, but it seems to be quite unstable at times * @author dosse * */ private class AdsController extends Thread { public void run() { while (optionsMenu == null) //wait for options menu to be created. this workaround is cheaper than an airPad 4 try { Thread.sleep(10); } catch (InterruptedException e) { } //there you go, fuckers: the CHEAPEST, CRAPPIEST license check ever, because LVL doesn't let me check the license of other apps (read pro key) anymore. thanks google, you fucktards. if (getPackageManager().checkSignatures(getPackageName(), "com.dosse.bwentrain.androidPlayerKey") == PackageManager.SIGNATURE_MATCH) { removeBuyOption(); } else { loadAds(); //let's tell ad block users to support us try { if (isPackageInstalled("tw.fatminmin.xposed.minminguard") || isPackageInstalled("org.adaway") || isPackageInstalled("org.adblockplus.android")) { try { openFileInput("minmin.fag"); } catch (Throwable t) { openFileOutput("minmin.fag", MODE_PRIVATE).close(); runOnUiThread(new Runnable() { @Override public void run() { startActivity(new Intent(MainActivity.this, MinMinFaggot.class)); } }); } } } catch (Throwable t) { Log.e("SINE", "Can't check for ad blockers " + t); } } //and they complain about piracy in android... } public boolean isPackageInstalled(String p) { try { getPackageManager().getPackageInfo(p, PackageManager.GET_META_DATA); return true; } catch (Throwable t) { return false; } } private void loadAds() { try { runOnUiThread(new Runnable() { @Override public void run() { try { ((AdView) findViewById(R.id.banner)).getLayoutParams().height = adsH; ((AdView) findViewById(R.id.banner)).loadAd(new AdRequest.Builder().build()); } catch (Throwable t) { } } }); } catch (Throwable t) { } } private void removeBuyOption() { try { runOnUiThread(new Runnable() { @Override public void run() { try { optionsMenu.getItem(0).setVisible(false); } catch (Throwable t) { } } }); } catch (Throwable t) { } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); NavigationView view = (NavigationView) findViewById(R.id.nav_view); DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); view.setNavigationItemSelectedListener(this); ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerToggle.syncState(); view.getMenu().getItem(0).setChecked(true); //hide ads, will be shown again if the app is not licensed adsH = ((AdView) findViewById(R.id.banner)).getLayoutParams().height; ((AdView) findViewById(R.id.banner)).getLayoutParams().height = 0; } @Override protected void onPostCreate(Bundle savedInstanceState) { new AdsController().start(); try { if (getIntent().getData() != null) { //called from an url Uri u = getIntent().getData(); if (u == null) throw new Exception(); String url = u.getScheme() + ":" + u.getEncodedSchemeSpecificPart(); if (url.toLowerCase().startsWith("http://sine.adolfintel.com/forum") || url.toLowerCase().startsWith("http://isochronic.io/forum")) startActivity(new Intent(this, CommunityActivity.class).putExtra("path", url)); //throw the url to the community activity else if (url.toLowerCase().startsWith("http://sine.adolfintel.com/goto.php") || url.toLowerCase().startsWith("http://sine.adolfintel.com/presets.php") || url.toLowerCase().startsWith("http://isochronic.io/goto.php") || url.toLowerCase().startsWith("http://isochronic.io/presets.php")) { //link to a preset, or to the preset page //attempt to convert to mobile and localized link try { String newUrl = getString(R.string.presets_url); //find preset id (if present) and add it to the new url String q = new URL(url).getQuery(); if (q != null) { String[] query = q.split("\\?"); for (String s : query) { String[] ss = s.split("="); if (ss[0].trim().equalsIgnoreCase("id")) { newUrl += "%26id=" + Integer.parseInt(ss[1].trim()); break; } } } Intent i = new Intent(this, BrowserActivity.class); i.putExtra("path", newUrl); startActivity(i); } catch (Throwable t) { Toast.makeText(getApplicationContext(), getString(R.string.community_invalid_presetId), Toast.LENGTH_SHORT).show(); } } else throw new Exception(); //ignore unknown urls } else throw new Exception(); } catch (Throwable t) { } try { openFileInput("material.run"); //material.run exists, go straight to the app } catch (Throwable t) { Intent i = new Intent(MainActivity.this, IntroActivity.class); try { openFileInput("first.run"); //first.run exists, the user just updated the app to the material design version, show update intro i.putExtra("update", true); } catch (Throwable t1) { //first.run does not exist, show intro i.putExtra("update", false); } startActivity(i); try { openFileOutput("material.run", MODE_PRIVATE).close(); } catch (Throwable t1) { } } super.onPostCreate(savedInstanceState); } @Override protected void onPause() { try { ((AdView) findViewById(R.id.banner)).pause(); } catch (Throwable t) { } super.onPause(); } @Override protected void onDestroy() { try { ((AdView) findViewById(R.id.banner)).destroy(); } catch (Throwable t) { } super.onDestroy(); } @Override protected void onResume() { try { ((AdView) findViewById(R.id.banner)).resume(); } catch (Throwable t) { } TextView status = (TextView) findViewById(R.id.textView1); SeekBar bar = (SeekBar) findViewById(R.id.seekBar1); Button playPause = (Button) findViewById(R.id.button1); //add action listener for seek bar bar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onStopTrackingTouch(SeekBar seekBar) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (!fromUser) return; pc.setPosition((float) progress / (float) seekBar.getMax()); } }); //add action listener for play/pause button playPause.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (pc.isPlaying()) pc.pause(); else pc.play(); } }); if (pc == null) { pc = new PlayerController(this, status, bar, playPause); //playercontroller not initialized, do it now } else { //playercontroller already initialized, give it pointers to the newly created views pc.setMainUI(this); pc.setStatusView(status); pc.setProgressView(bar); pc.setButton(playPause); } populatePresetList(); ((NavigationView) findViewById(R.id.nav_view)).getMenu().getItem(0).setChecked(true); super.onResume(); } @Override //receives intents from DetailsActivity, and loads the selected preset. if no path is set, then the intent came from some other activity and does nothing public void onNewIntent(Intent i) { String request = i.getStringExtra("path"); if (request != null) { Preset p = loadPreset(request); if (pc == null) { //I got some bug reports where the PlayerController was null. This should not be possible, and I was not able to replicate the bug so I'll just try to restart the activity. Hopefully it will fix the bug? startActivity(new Intent(this, MainActivity.class).putExtra("path", request) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)); finish(); } if (p != null) pc.setPreset(p); else Toast.makeText(getApplicationContext(), R.string.load_error, Toast.LENGTH_SHORT).show(); } super.onNewIntent(i); } private Preset loadPreset(String f) { InputStream p = null; Preset x = null; try { if (new File(f).exists()) p = new FileInputStream(f); else p = openFileInput(f); if (p == null) throw new Exception("Can't open " + f); //read xml document DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); factory.setValidating(false); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(p); doc.getDocumentElement().normalize(); //parse it x = new Preset(doc.getDocumentElement()); if (getSharedPreferences("SINE", Context.MODE_PRIVATE).getBoolean("noise_switch", false)) { //if noise is disabled, remove it Envelope e = x.getNoiseEnvelope(); while (e.getPointCount() != 1) e.removePoint(1); e.setVal(0, 0); } } catch (Throwable t) { //corrupt or not a preset file Log.e("SINE", f + " invalid because " + t.toString()); } finally { if (p != null) try { p.close(); } catch (IOException e) { } } return x; } private void populatePresetList() { final ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>(); ArrayList<String> fileList = new ArrayList<String>(); String[] downloads = fileList(); //get all files downloaded from the preset sharing platform for (String s : downloads) //add all downloaded presets if (s.toLowerCase().endsWith(".sin")) { fileList.add(s); } //generate items for ListView //add link to preset sharing platform HashMap<String, String> siteLink = new HashMap<String, String>(); siteLink.put("title", getString(R.string.download_presets)); siteLink.put("author", getString(R.string.theyre_free)); siteLink.put("description", ""); siteLink.put("path", getString(R.string.presets_url)); list.add(siteLink); for (String f : fileList) { Preset p = loadPreset(f); if (p == null) continue; HashMap<String, String> item = new HashMap<String, String>(); item.put("title", p.getTitle()); item.put("author", p.getAuthor()); item.put("description", p.getDescription()); item.put("length", "" + Utils.toHMS(p.getLength())); item.put("loop", "" + (p.loops() ? Utils.toHMS(p.getLoop()) : "")); item.put("path", f); list.add(item); } //insert all into ListView ListView files = (ListView) findViewById(R.id.listView1); files.setAdapter(new SimpleAdapter(this, list, android.R.layout.simple_list_item_2, new String[] { "title", "author" }, new int[] { android.R.id.text1, android.R.id.text2 })); //tap on item files.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { HashMap<String, String> item = list.get(position); if (item.get("path").startsWith("http://")) { //link Intent i = new Intent(MainActivity.this, BrowserActivity.class); i.putExtra("path", item.get("path")); startActivity(i); } else { //preset Intent i = new Intent(MainActivity.this, DetailsActivity.class); i.putExtra("title", item.get("title")); i.putExtra("author", item.get("author")); i.putExtra("description", item.get("description")); i.putExtra("length", item.get("length")); i.putExtra("loop", item.get("loop")); i.putExtra("path", item.get("path")); startActivity(i); } } }); //long tap on item files.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { HashMap<String, String> item = list.get(position); final String path = item.get("path"); if (path.startsWith("http://")) return true; //can't delete links //delete preset //ask for confirm AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); DialogInterface.OnClickListener l = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { //delete confirmed if (new File(path).exists()) { //delete file on sdcard new File(path).delete(); } else {//delete from app data deleteFile(path); } populatePresetList(); //repopulate preset list } } }; builder.setMessage(getString(R.string.delete_confirm) + " \"" + item.get("title") + "\"?") .setPositiveButton(getString(R.string.yes), l).setNegativeButton(getString(R.string.no), l) .show(); return true; } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); optionsMenu = menu; return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); try { if (id == R.id.purchase) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.purchase_url)))); } if (id == R.id.playStore) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.playStore_url)))); } if (id == R.id.fb) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.fb_url)))); } if (id == R.id.tw) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.tw_url)))); } if (id == R.id.gp) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.gp_url)))); } if (id == R.id.web) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.website_url)))); } if (id == R.id.settings) { startActivity(new Intent(this, SettingsActivity.class)); } if (id == R.id.about) { startActivity(new Intent(this, AboutActivity.class)); } if (id == R.id.exit) { //cancel notifications, kill service and quit ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0); if (pc != null) pc.killService(); Thread.sleep(100); System.exit(0); } } catch (Throwable t) { //ignore all errors } return super.onOptionsItemSelected(item); } @Override public boolean onNavigationItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.nav_presets) { startActivity( new Intent(this, BrowserActivity.class).putExtra("path", getString(R.string.presets_url))); } if (id == R.id.nav_community) { startActivity( new Intent(this, CommunityActivity.class).putExtra("path", getString(R.string.forum_url))); } if (id == R.id.nav_settings) { startActivity(new Intent(this, SettingsActivity.class)); } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } }