diff --git a/build.gradle b/build.gradle index 6ba27252..5ab17d01 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.2' + classpath 'com.android.tools.build:gradle:8.0.2' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10' // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle.properties b/gradle.properties index bdf3872b..f2015a2a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,3 +22,6 @@ org.gradle.workers.max=16 android.defaults.buildfeatures.renderscript = false android.defaults.buildfeatures.shaders = false +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 50535547..42b24476 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Apr 22 21:25:44 MSK 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/poweramp_api_example/build.gradle b/poweramp_api_example/build.gradle index 1d162079..5893f7f7 100644 --- a/poweramp_api_example/build.gradle +++ b/poweramp_api_example/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdk 33 - buildToolsVersion '33.0.0' + buildToolsVersion '34.0.0' defaultConfig { applicationId "com.maxmpz.poweramp.apiexample" @@ -22,6 +22,11 @@ android { targetCompatibility JavaVersion.VERSION_11 } namespace 'com.maxmpz.poweramp.apiexample' + dependenciesInfo { + includeInApk true + includeInBundle true + } + ndkVersion ndkVersion } diff --git a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/APIReceiver.java b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/APIReceiver.java index 7a9d5533..12283bed 100644 --- a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/APIReceiver.java +++ b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/APIReceiver.java @@ -34,20 +34,20 @@ public class APIReceiver extends BroadcastReceiver { private static final String TAG = "APIReceiver"; @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if(action != null) { + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + if(null != action) { switch(action) { case PowerampAPI.ACTION_STATUS_CHANGED_EXPLICIT: - MainActivity.debugDumpIntent(TAG, "ACTION_STATUS_CHANGED_EXPLICIT", intent); + MainActivity.debugDumpIntent(APIReceiver.TAG, "ACTION_STATUS_CHANGED_EXPLICIT", intent); break; case PowerampAPI.ACTION_TRACK_CHANGED_EXPLICIT: - MainActivity.debugDumpIntent(TAG, "ACTION_TRACK_CHANGED_EXPLICIT", intent); + MainActivity.debugDumpIntent(APIReceiver.TAG, "ACTION_TRACK_CHANGED_EXPLICIT", intent); break; default: - MainActivity.debugDumpIntent(TAG, "UNKNOWN", intent); + MainActivity.debugDumpIntent(APIReceiver.TAG, "UNKNOWN", intent); break; } } diff --git a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/EqActivity.java b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/EqActivity.java index d578952b..de41a9cf 100644 --- a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/EqActivity.java +++ b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/EqActivity.java @@ -32,17 +32,12 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import android.os.Bundle; import android.util.Log; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.SimpleCursorAdapter; -import android.widget.SimpleCursorAdapter.ViewBinder; import android.widget.Spinner; import android.widget.TableLayout; import android.widget.TableRow; @@ -50,7 +45,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import com.maxmpz.poweramp.player.PowerampAPI; import com.maxmpz.poweramp.player.PowerampAPIHelper; -public class EqActivity extends Activity implements OnClickListener, OnCheckedChangeListener, OnSeekBarChangeListener, OnItemSelectedListener { +public class EqActivity extends Activity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener, SeekBar.OnSeekBarChangeListener, AdapterView.OnItemSelectedListener { private static final String TAG = "EqActivity"; private static final boolean LOG = true; @@ -66,39 +61,39 @@ public class EqActivity extends Activity implements OnClickListener, OnCheckedCh @SuppressWarnings({ "resource", "deprecation" }) @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Ask for PA equ state update immediately by sending "empty" SET_EQU_ENABLED command. // The reply may be delayed up to 250ms, so UI should accommodate for that (update asynchronously) - requestEqStatus(); + this.requestEqStatus(); setContentView(R.layout.activity_eq); - ((CheckBox)findViewById(R.id.dynamic)).setOnCheckedChangeListener(this); - findViewById(R.id.commit_eq).setOnClickListener(this); + ((CheckBox) this.findViewById(R.id.dynamic)).setOnCheckedChangeListener(this); + this.findViewById(R.id.commit_eq).setOnClickListener(this); // Create and bind spinner which binds to available Poweramp presets. - Spinner presetSpinner = (Spinner)findViewById(R.id.preset_spinner); - String[] cols = new String[] { "_id", "name" }; - Cursor c = getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("eq_presets").build(), + final Spinner presetSpinner = this.findViewById(R.id.preset_spinner); + final String[] cols = { "_id", "name" }; + final Cursor c = this.getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("eq_presets").build(), cols, null, null, "name"); - if(c != null) startManagingCursor(c); + if(null != c) this.startManagingCursor(c); // Add first empty item to the merged cursor via matrix cursor with single row. - MatrixCursor mc = new MatrixCursor(cols); + final MatrixCursor mc = new MatrixCursor(cols); mc.addRow(new Object[]{ PowerampAPI.NO_ID, "" }); - MergeCursor mrgc = new MergeCursor(new Cursor[]{ mc, c }); + final MergeCursor mrgc = new MergeCursor(new Cursor[]{ mc, c }); - SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, + final SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_dropdown_item, mrgc, new String[] { "name" }, new int[] { android.R.id.text1 }, 0); - adapter.setViewBinder(new ViewBinder() { + adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { @Override - public boolean setViewValue(View view, Cursor cursor, int columnIndex) { + public boolean setViewValue(final View view, final Cursor cursor, final int columnIndex) { ((TextView)view).setText(cursor.getString(1)); return true; } @@ -107,8 +102,8 @@ public boolean setViewValue(View view, Cursor cursor, int columnIndex) { presetSpinner.setAdapter(adapter); presetSpinner.setOnItemSelectedListener(this); - ((CheckBox)findViewById(R.id.eq)).setOnCheckedChangeListener(this); - ((CheckBox)findViewById(R.id.tone)).setOnCheckedChangeListener(this); + ((CheckBox) this.findViewById(R.id.eq)).setOnCheckedChangeListener(this); + ((CheckBox) this.findViewById(R.id.tone)).setOnCheckedChangeListener(this); } private void requestEqStatus() { @@ -122,11 +117,11 @@ private void requestEqStatus() { * As this activity always syncs everything with the actual state of Poweramp, this automatic restoring of state is just non needed. */ @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(final Bundle outState) { } @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { + protected void onRestoreInstanceState(final Bundle savedInstanceState) { } @@ -136,7 +131,7 @@ protected void onRestoreInstanceState(Bundle savedInstanceState) { */ @Override protected void onPause() { - unregister(); + this.unregister(); super.onPause(); } @@ -148,19 +143,19 @@ protected void onPause() { protected void onResume() { super.onResume(); - registerAndLoadStatus(); + this.registerAndLoadStatus(); // Ask PA for eq state as, while on background, we probably were denied of intent processing due to // Android 8+ background limitations - requestEqStatus(); + this.requestEqStatus(); } @Override protected void onDestroy() { - unregister(); + this.unregister(); - mEquReceiver = null; + this.mEquReceiver = null; super.onDestroy(); } @@ -172,74 +167,74 @@ protected void onDestroy() { * NOTE: For Poweramp v3 this intent is not sticky anymore */ private void registerAndLoadStatus() { - mEquIntent = registerReceiver(mEquReceiver, new IntentFilter(PowerampAPI.ACTION_EQU_CHANGED)); - if(LOG) Log.w(TAG, "registerAndLoadStatus mEquIntent=>" + mEquIntent); + this.mEquIntent = this.registerReceiver(this.mEquReceiver, new IntentFilter(PowerampAPI.ACTION_EQU_CHANGED)); + if(EqActivity.LOG) Log.w(EqActivity.TAG, "registerAndLoadStatus mEquIntent=>" + this.mEquIntent); } private void unregister() { - if(mEquReceiver != null) { + if(null != mEquReceiver) { try { - unregisterReceiver(mEquReceiver); - } catch(Exception ignored) { + this.unregisterReceiver(this.mEquReceiver); + } catch(final Exception ignored) { } } } private BroadcastReceiver mEquReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - mEquIntent = intent; + public void onReceive(final Context context, final Intent intent) { + EqActivity.this.mEquIntent = intent; - if(LOG) debugDumpEquIntent(intent); + if(EqActivity.LOG) EqActivity.this.debugDumpEquIntent(intent); - updateEqu(); + EqActivity.this.updateEqu(); } }; void updateEqu() { - if(mEquIntent == null) { - if(LOG) Log.e(TAG, "updateEqu IGNORE !mEquIntent"); + if(null == mEquIntent) { + if(EqActivity.LOG) Log.e(EqActivity.TAG, "updateEqu IGNORE !mEquIntent"); return; } - if(LOG) Log.w(TAG, "updateEqu", new Exception()); + if(EqActivity.LOG) Log.w(EqActivity.TAG, "updateEqu", new Exception()); - final CheckBox eq = (CheckBox)findViewById(R.id.eq); - boolean equEnabled = mEquIntent.getBooleanExtra(PowerampAPI.EXTRA_EQU, false); + CheckBox eq = this.findViewById(R.id.eq); + final boolean equEnabled = this.mEquIntent.getBooleanExtra(PowerampAPI.EXTRA_EQU, false); if(eq.isChecked() != equEnabled) { - mSettingEqu = true; + this.mSettingEqu = true; eq.setChecked(equEnabled); } - final CheckBox tone = (CheckBox)findViewById(R.id.tone); - boolean toneEnabled = mEquIntent.getBooleanExtra(PowerampAPI.EXTRA_TONE, false); + CheckBox tone = this.findViewById(R.id.tone); + final boolean toneEnabled = this.mEquIntent.getBooleanExtra(PowerampAPI.EXTRA_TONE, false); if(tone.isChecked() != toneEnabled) { - mSettingTone = true; + this.mSettingTone = true; tone.setChecked(toneEnabled); } - String presetString = mEquIntent.getStringExtra(PowerampAPI.EXTRA_VALUE); - if(presetString == null || presetString.length() == 0) { - if(LOG) Log.w(TAG, "updateEqu !presetString"); + final String presetString = this.mEquIntent.getStringExtra(PowerampAPI.EXTRA_VALUE); + if(null == presetString || 0 == presetString.length()) { + if(EqActivity.LOG) Log.w(EqActivity.TAG, "updateEqu !presetString"); return; } - if(!mEquBuilt) { - buildEquUI(presetString); - mEquBuilt = true; + if(!this.mEquBuilt) { + this.buildEquUI(presetString); + this.mEquBuilt = true; } else { - updateEquUI(presetString); + this.updateEquUI(presetString); } - long id = mEquIntent.getLongExtra(PowerampAPI.EXTRA_ID, PowerampAPI.NO_ID); - if(LOG) Log.w(TAG, "updateEqu id=" + id); + final long id = this.mEquIntent.getLongExtra(PowerampAPI.EXTRA_ID, PowerampAPI.NO_ID); + if(EqActivity.LOG) Log.w(EqActivity.TAG, "updateEqu id=" + id); - Spinner presetSpinner = (Spinner)findViewById(R.id.preset_spinner); - int count = presetSpinner.getAdapter().getCount(); + final Spinner presetSpinner = this.findViewById(R.id.preset_spinner); + final int count = presetSpinner.getAdapter().getCount(); for(int i = 0; i < count; i++) { if(presetSpinner.getAdapter().getItemId(i) == id) { if(presetSpinner.getSelectedItemPosition() != i) { - mSettingPreset = true; + this.mSettingPreset = true; presetSpinner.setSelection(i); } break; @@ -250,38 +245,38 @@ void updateEqu() { /** * This method parses the equalizer serialized "presetString" and creates appropriate seekbars. */ - private void buildEquUI(String string) { - if(LOG) Log.w(TAG, "buildEquUI string=" + string); - String[] pairs = sSemicolonSplitRe.split(string); - TableLayout equLayout = (TableLayout)findViewById(R.id.equ_layout); + private void buildEquUI(final String string) { + if(EqActivity.LOG) Log.w(EqActivity.TAG, "buildEquUI string=" + string); + final String[] pairs = EqActivity.sSemicolonSplitRe.split(string); + final TableLayout equLayout = this.findViewById(R.id.equ_layout); - for(String pair : pairs) { - String[] nameValue = sEqualSplitRe.split(pair, 2); - if(nameValue.length == 2) { - String name = nameValue[0]; + for(final String pair : pairs) { + final String[] nameValue = EqActivity.sEqualSplitRe.split(pair, 2); + if(2 == nameValue.length) { + final String name = nameValue[0]; try { - float value = Float.parseFloat(nameValue[1]); + final float value = Float.parseFloat(nameValue[1]); - TableRow row = new TableRow(this); + final TableRow row = new TableRow(this); - TextView label = new TextView(this); + final TextView label = new TextView(this); label.setText(name); - TableRow.LayoutParams lp = new TableRow.LayoutParams(); - lp.height = lp.width = TableRow.LayoutParams.WRAP_CONTENT; + final TableRow.LayoutParams lp = new TableRow.LayoutParams(); + lp.height = lp.width = ViewGroup.LayoutParams.WRAP_CONTENT; row.addView(label, lp); - SeekBar bar = new SeekBar(this); + final SeekBar bar = new SeekBar(this); bar.setOnSeekBarChangeListener(this); bar.setTag(name); - setBandValue(name, value, bar); + this.setBandValue(name, value, bar); row.addView(bar, lp); equLayout.addView(row); - } catch(NumberFormatException ex) { + } catch(final NumberFormatException ex) { ex.printStackTrace(); - Log.e(TAG, "failed to parse eq value=" + nameValue[1]); + Log.e(EqActivity.TAG, "failed to parse eq value=" + nameValue[1]); } } } @@ -290,64 +285,64 @@ private void buildEquUI(String string) { /** * Preamp, bass/treble and equ bands have different scaling. This method ensures correct scaling is applied. */ - void setBandValue(String name, float value, SeekBar bar) { - if(LOG) Log.w(TAG, "setBandValue name=" + name + " value=" + value); + void setBandValue(final String name, final float value, final SeekBar bar) { + if(EqActivity.LOG) Log.w(EqActivity.TAG, "setBandValue name=" + name + " value=" + value); if("preamp".equals(name)) { bar.setMax(200); - bar.setProgress((int)(value * 100f)); + bar.setProgress((int)(value * 100.0f)); } else if("bass".equals(name) || "treble".equals(name)) { bar.setMax(100); - bar.setProgress((int)(value * 100f)); + bar.setProgress((int)(value * 100.0f)); } else { bar.setMax(200); - bar.setProgress((int)(value * 100f + 100f)); + bar.setProgress((int)(value * 100.0f + 100.0f)); } } /** * Almost the same as buildEquUI, just do the UI update without building it */ - private void updateEquUI(String string) { - if(LOG) Log.w(TAG, "updateEquUI string=" + string); - String[] pairs = sSemicolonSplitRe.split(string); - TableLayout equLayout = (TableLayout)findViewById(R.id.equ_layout); + private void updateEquUI(final String string) { + if(EqActivity.LOG) Log.w(EqActivity.TAG, "updateEquUI string=" + string); + final String[] pairs = EqActivity.sSemicolonSplitRe.split(string); + final TableLayout equLayout = this.findViewById(R.id.equ_layout); for(int i = 0, pairsLength = pairs.length; i < pairsLength; i++) { - String[] nameValue = sEqualSplitRe.split(pairs[i], 2); - if(nameValue.length == 2) { - String name = nameValue[0]; + final String[] nameValue = EqActivity.sEqualSplitRe.split(pairs[i], 2); + if(2 == nameValue.length) { + final String name = nameValue[0]; try { - float value = Float.parseFloat(nameValue[1]); + final float value = Float.parseFloat(nameValue[1]); - SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); - if(bar == null) { - Log.w(TAG, "no bar=" + name); + final SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); + if(null == bar) { + Log.w(EqActivity.TAG, "no bar=" + name); continue; } - setBandValue(name, value, bar); - } catch(NumberFormatException ex) { + this.setBandValue(name, value, bar); + } catch(final NumberFormatException ex) { ex.printStackTrace(); - Log.e(TAG, "failed to parse eq value=" + nameValue[1]); + Log.e(EqActivity.TAG, "failed to parse eq value=" + nameValue[1]); } } } } - void debugDumpEquIntent(Intent intent) { - if(intent != null) { - String presetName = intent.getStringExtra(PowerampAPI.EXTRA_NAME); - String presetString = intent.getStringExtra(PowerampAPI.EXTRA_VALUE); - long id = mEquIntent.getLongExtra(PowerampAPI.EXTRA_ID, PowerampAPI.NO_ID); - Log.w(TAG, "debugDumpEquIntent presetName=" + presetName + " presetString=" + presetString + " id=" + id); + void debugDumpEquIntent(final Intent intent) { + if(null != intent) { + final String presetName = intent.getStringExtra(PowerampAPI.EXTRA_NAME); + final String presetString = intent.getStringExtra(PowerampAPI.EXTRA_VALUE); + final long id = this.mEquIntent.getLongExtra(PowerampAPI.EXTRA_ID, PowerampAPI.NO_ID); + Log.w(EqActivity.TAG, "debugDumpEquIntent presetName=" + presetName + " presetString=" + presetString + " id=" + id); } else { - Log.e(TAG, "debugDumpEquIntent: intent is null"); + Log.e(EqActivity.TAG, "debugDumpEquIntent: intent is null"); } } @Override - public void onClick(View v) { + public void onClick(final View v) { if(v.getId() == R.id.commit_eq) { - commitEq(); + this.commitEq(); } } @@ -355,29 +350,29 @@ public void onClick(View v) { * Event handler for the checkboxes */ @Override - public void onCheckedChanged(CompoundButton view, boolean isChecked) { - Log.w(TAG, "onCheckedChanged=" + view); - int id = view.getId(); + public void onCheckedChanged(final CompoundButton view, final boolean isChecked) { + Log.w(EqActivity.TAG, "onCheckedChanged=" + view); + final int id = view.getId(); if(id == R.id.dynamic) { - findViewById(R.id.commit_eq).setEnabled(!isChecked); + this.findViewById(R.id.commit_eq).setEnabled(!isChecked); } else if(id == R.id.eq) { - if(!mSettingEqu) { + if(!this.mSettingEqu) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_ENABLED) .putExtra(PowerampAPI.EXTRA_EQU, isChecked), MainActivity.FORCE_API_ACTIVITY ); } - mSettingEqu = false; + this.mSettingEqu = false; } else if(id == R.id.tone) { - if(!mSettingTone) { + if(!this.mSettingTone) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_ENABLED) .putExtra(PowerampAPI.EXTRA_TONE, isChecked), MainActivity.FORCE_API_ACTIVITY ); } - mSettingTone = false; + this.mSettingTone = false; } } @@ -385,14 +380,14 @@ public void onCheckedChanged(CompoundButton view, boolean isChecked) { * Generates and sends presetString to Poweramp */ private void commitEq() { - StringBuilder presetString = new StringBuilder(); - - TableLayout equLayout = (TableLayout)findViewById(R.id.equ_layout); - int count = equLayout.getChildCount(); - for(int i = count - 1; i >= 0; i--) { - SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); - String name = (String)bar.getTag(); - float value = seekBarToValue(name, bar.getProgress()); + final StringBuilder presetString = new StringBuilder(); + + final TableLayout equLayout = this.findViewById(R.id.equ_layout); + final int count = equLayout.getChildCount(); + for(int i = count - 1; 0 <= i; i--) { + final SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); + final String name = (String)bar.getTag(); + final float value = this.seekBarToValue(name, bar.getProgress()); presetString.append(name).append("=").append(value).append(";"); } @@ -406,12 +401,12 @@ private void commitEq() { /** * Applies correct seekBar-to-float scaling */ - private float seekBarToValue(String name, int progress) { - float value; + private float seekBarToValue(final String name, final int progress) { + final float value; if("preamp".equals(name) || "bass".equals(name) || "treble".equals(name)) { - value = (float)progress / 100.f; + value = progress / 100.0f; } else { - value = (float)(progress - 100) / 100.f; + value = (progress - 100) / 100.0f; } return value; } @@ -420,11 +415,11 @@ private float seekBarToValue(String name, int progress) { * Process Eq band change. */ @Override - public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) { + public void onProgressChanged(final SeekBar bar, final int progress, final boolean fromUser) { - if(((CheckBox)findViewById(R.id.dynamic)).isChecked()) { - String name = (String)bar.getTag(); - float value = seekBarToValue(name, bar.getProgress()); + if(((CheckBox) this.findViewById(R.id.dynamic)).isChecked()) { + final String name = (String)bar.getTag(); + final float value = this.seekBarToValue(name, bar.getProgress()); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_BAND) .putExtra(PowerampAPI.EXTRA_NAME, name) @@ -435,30 +430,30 @@ public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) { } @Override - public void onStartTrackingTouch(SeekBar seekBar) { + public void onStartTrackingTouch(final SeekBar seekBar) { } @Override - public void onStopTrackingTouch(SeekBar seekBar) { + public void onStopTrackingTouch(final SeekBar seekBar) { } /** * Event handler for Presets spinner */ @Override - public void onItemSelected(AdapterView adapter, View item, int pos, long id) { - if(!mSettingPreset) { + public void onItemSelected(final AdapterView adapter, final View item, final int pos, final long id) { + if(!this.mSettingPreset) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_PRESET) .putExtra(PowerampAPI.EXTRA_ID, id), MainActivity.FORCE_API_ACTIVITY ); } else { - mSettingPreset = false; + this.mSettingPreset = false; } } @Override - public void onNothingSelected(AdapterView arg0) { + public void onNothingSelected(final AdapterView arg0) { } } \ No newline at end of file diff --git a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/FoldersActivity.java b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/FoldersActivity.java index b3ebb233..6970d2b2 100644 --- a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/FoldersActivity.java +++ b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/FoldersActivity.java @@ -31,43 +31,41 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import android.util.Log; import android.view.View; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; import android.widget.SimpleCursorAdapter; @SuppressWarnings("deprecation") -public class FoldersActivity extends ListActivity implements OnItemClickListener, OnItemLongClickListener { +public class FoldersActivity extends ListActivity implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener { private static final String TAG = "FoldersActivity"; @Override - protected void onCreate(Bundle savedInstanceState){ + protected void onCreate(final Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_folders); - Cursor c = this.getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").build(), + final Cursor c = getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").build(), new String[]{ "folders._id AS _id", "folders.name AS name", "folders.parent_name AS parent_name" }, null, null, "folders.name COLLATE NOCASE"); - if(c != null) startManagingCursor(c); + if(null != c) this.startManagingCursor(c); - SimpleCursorAdapter adapter = new SimpleCursorAdapter( + final SimpleCursorAdapter adapter = new SimpleCursorAdapter( this, // Context. android.R.layout.two_line_list_item, c, new String[] { "name", "parent_name" }, new int[] {android.R.id.text1, android.R.id.text2}); - setListAdapter(adapter); + this.setListAdapter(adapter); - ListView list = (ListView)findViewById(android.R.id.list); + final ListView list = this.findViewById(android.R.id.list); list.setOnItemClickListener(this); list.setOnItemLongClickListener(this); } @Override - public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, long id) { - Log.w(TAG, "folder long press=" + id); + public boolean onItemLongClick(final AdapterView arg0, final View arg1, final int arg2, final long id) { + Log.w(FoldersActivity.TAG, "folder long press=" + id); - Uri.Builder uriB = PowerampAPI.ROOT_URI.buildUpon() + final Uri.Builder uriB = PowerampAPI.ROOT_URI.buildUpon() .appendEncodedPath("folders") .appendEncodedPath(Long.toString(id)) .appendQueryParameter(PowerampAPI.PARAM_SHUFFLE, Integer.toString(PowerampAPI.ShuffleMode.SHUFFLE_SONGS)); @@ -77,16 +75,16 @@ public boolean onItemLongClick(AdapterView arg0, View arg1, int arg2, long id .setData(uriB.build()), MainActivity.FORCE_API_ACTIVITY ); - finish(); + this.finish(); return true; } @Override - public void onItemClick(AdapterView arg0, View arg1, int arg2, long id) { - Log.w(TAG, "folder press=" + id); + public void onItemClick(final AdapterView arg0, final View arg1, final int arg2, final long id) { + Log.w(FoldersActivity.TAG, "folder press=" + id); - Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").appendEncodedPath(Long.toString(id)).appendEncodedPath("files").build(); + final Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").appendEncodedPath(Long.toString(id)).appendEncodedPath("files").build(); - startActivity(new Intent(this, TrackListActivity.class).setData(filesUri)); + this.startActivity(new Intent(this, TrackListActivity.class).setData(filesUri)); } } diff --git a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/MainActivity.java b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/MainActivity.java index 0534350f..89c48fb9 100644 --- a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/MainActivity.java +++ b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/MainActivity.java @@ -44,20 +44,14 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import android.util.Log; import android.view.MotionEvent; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; -import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.ImageView; import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; @@ -67,7 +61,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import com.maxmpz.poweramp.player.PowerampAPI; import com.maxmpz.poweramp.player.PowerampAPIHelper; import com.maxmpz.poweramp.player.RemoteTrackTime; -import com.maxmpz.poweramp.player.RemoteTrackTime.TrackTimeListener; import com.maxmpz.poweramp.player.TableDefs; import org.eclipse.jdt.annotation.NonNull; @@ -77,13 +70,13 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public class MainActivity extends AppCompatActivity implements - OnClickListener, - OnLongClickListener, - OnTouchListener, - OnCheckedChangeListener, - OnSeekBarChangeListener, - OnItemSelectedListener, - TrackTimeListener + View.OnClickListener, + View.OnLongClickListener, + View.OnTouchListener, + CompoundButton.OnCheckedChangeListener, + SeekBar.OnSeekBarChangeListener, + AdapterView.OnItemSelectedListener, + RemoteTrackTime.TrackTimeListener { private static final String TAG = "MainActivity"; private static final boolean LOG_VERBOSE = false; @@ -91,7 +84,7 @@ public class MainActivity extends AppCompatActivity implements /** If set to true, we send all our intents to API activity. Use for Poweramp build 862+ */ static final boolean FORCE_API_ACTIVITY = true; - private static final char[] NO_TIME = new char[]{ '-', ':', '-', '-' }; + private static final char[] NO_TIME = { '-', ':', '-', '-' }; private static final int SEEK_THROTTLE = 500; protected Intent mTrackIntent; @@ -120,82 +113,82 @@ public class MainActivity extends AppCompatActivity implements @Override - public void onCreate(Bundle savedInstanceState) { - if(LOG_VERBOSE) Log.w(TAG, "onCreate"); + public void onCreate(final Bundle savedInstanceState) { + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - findViewById(R.id.play).setOnClickListener(this); - findViewById(R.id.play).setOnLongClickListener(this); - findViewById(R.id.pause).setOnClickListener(this); + this.findViewById(R.id.play).setOnClickListener(this); + this.findViewById(R.id.play).setOnLongClickListener(this); + this.findViewById(R.id.pause).setOnClickListener(this); - findViewById(R.id.prev).setOnClickListener(this); - findViewById(R.id.prev).setOnLongClickListener(this); - findViewById(R.id.prev).setOnTouchListener(this); + this.findViewById(R.id.prev).setOnClickListener(this); + this.findViewById(R.id.prev).setOnLongClickListener(this); + this.findViewById(R.id.prev).setOnTouchListener(this); - findViewById(R.id.next).setOnClickListener(this); - findViewById(R.id.next).setOnLongClickListener(this); - findViewById(R.id.next).setOnTouchListener(this); + this.findViewById(R.id.next).setOnClickListener(this); + this.findViewById(R.id.next).setOnLongClickListener(this); + this.findViewById(R.id.next).setOnTouchListener(this); - findViewById(R.id.prev_in_cat).setOnClickListener(this); - findViewById(R.id.next_in_cat).setOnClickListener(this); - findViewById(R.id.repeat).setOnClickListener(this); - findViewById(R.id.shuffle).setOnClickListener(this); - findViewById(R.id.repeat_all).setOnClickListener(this); - findViewById(R.id.repeat_off).setOnClickListener(this); - findViewById(R.id.shuffle_all).setOnClickListener(this); - findViewById(R.id.shuffle_off).setOnClickListener(this); - findViewById(R.id.eq).setOnClickListener(this); + this.findViewById(R.id.prev_in_cat).setOnClickListener(this); + this.findViewById(R.id.next_in_cat).setOnClickListener(this); + this.findViewById(R.id.repeat).setOnClickListener(this); + this.findViewById(R.id.shuffle).setOnClickListener(this); + this.findViewById(R.id.repeat_all).setOnClickListener(this); + this.findViewById(R.id.repeat_off).setOnClickListener(this); + this.findViewById(R.id.shuffle_all).setOnClickListener(this); + this.findViewById(R.id.shuffle_off).setOnClickListener(this); + this.findViewById(R.id.eq).setOnClickListener(this); - mSongSeekBar = findViewById(R.id.song_seekbar); - mSongSeekBar.setOnSeekBarChangeListener(this); + this.mSongSeekBar = this.findViewById(R.id.song_seekbar); + this.mSongSeekBar.setOnSeekBarChangeListener(this); - mDuration = findViewById(R.id.duration); - mElapsed = findViewById(R.id.elapsed); + this.mDuration = this.findViewById(R.id.duration); + this.mElapsed = this.findViewById(R.id.elapsed); - mRemoteTrackTime = new RemoteTrackTime(this); - mRemoteTrackTime.setTrackTimeListener(this); + this.mRemoteTrackTime = new RemoteTrackTime(this); + this.mRemoteTrackTime.setTrackTimeListener(this); //((TextView)findViewById(R.id.play_file_path)).setText(findFirstMP3(Environment.getExternalStorageDirectory())); // This can be slow, disabled - findViewById(R.id.play_file).setOnClickListener(this); + this.findViewById(R.id.play_file).setOnClickListener(this); - findViewById(R.id.folders).setOnClickListener(this); + this.findViewById(R.id.folders).setOnClickListener(this); - findViewById(R.id.play_album).setOnClickListener(this); - findViewById(R.id.play_all_songs).setOnClickListener(this); - findViewById(R.id.play_second_artist_first_album).setOnClickListener(this); + this.findViewById(R.id.play_album).setOnClickListener(this); + this.findViewById(R.id.play_all_songs).setOnClickListener(this); + this.findViewById(R.id.play_second_artist_first_album).setOnClickListener(this); - findViewById(R.id.pa_current_list).setOnClickListener(this); - findViewById(R.id.pa_folders).setOnClickListener(this); - findViewById(R.id.pa_all_songs).setOnClickListener(this); - ((SeekBar)findViewById(R.id.sleep_timer_seekbar)).setOnSeekBarChangeListener(this); + this.findViewById(R.id.pa_current_list).setOnClickListener(this); + this.findViewById(R.id.pa_folders).setOnClickListener(this); + this.findViewById(R.id.pa_all_songs).setOnClickListener(this); + ((SeekBar) this.findViewById(R.id.sleep_timer_seekbar)).setOnSeekBarChangeListener(this); // Ask Poweramp for a permission to access its data provider. Needed only if we want to make queries against Poweramp database, e.g. in FilesActivity/FoldersActivity // NOTE: this will work only if Poweramp process is alive. // This actually should be done once per this app installation, but for the simplicity, we use per-process static field here - if(!sPermissionAsked) { - if(LOG_VERBOSE) Log.w(TAG, "onCreate skin permission"); - Intent intent = new Intent(PowerampAPI.ACTION_ASK_FOR_DATA_PERMISSION); + if(!MainActivity.sPermissionAsked) { + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "onCreate skin permission"); + final Intent intent = new Intent(PowerampAPI.ACTION_ASK_FOR_DATA_PERMISSION); intent.setPackage(PowerampAPIHelper.getPowerampPackageName(this)); - intent.putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); - if(FORCE_API_ACTIVITY) { + intent.putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); + if(MainActivity.FORCE_API_ACTIVITY) { intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); - startActivitySafe(intent); + this.startActivitySafe(intent); } else { - sendBroadcast(intent); + this.sendBroadcast(intent); } - sPermissionAsked = true; + MainActivity.sPermissionAsked = true; } - getComponentNames(); + this.getComponentNames(); - if(PowerampAPIHelper.getPowerampBuild(this) == 0) { - var topHint = (TextView)findViewById(R.id.top_hint); + if(0 == PowerampAPIHelper.getPowerampBuild(this)) { + final var topHint = (TextView) this.findViewById(R.id.top_hint); topHint.setText("-Poweramp not installed-"); topHint.setVisibility(VISIBLE); } - if(LOG_VERBOSE) Log.w(TAG, "onCreate DONE"); + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "onCreate DONE"); } /** @@ -207,14 +200,14 @@ public void onCreate(Bundle savedInstanceState) { * state otherwise, as empty onSaveInstanceState here denies save for everything */ @Override - public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { + public void onSaveInstanceState(final Bundle outState, final PersistableBundle outPersistentState) { } /** * @see #onSaveInstanceState */ @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { + protected void onRestoreInstanceState(final Bundle savedInstanceState) { } /** @@ -224,8 +217,8 @@ protected void onRestoreInstanceState(Bundle savedInstanceState) { */ @Override protected void onPause() { - unregister(); - mRemoteTrackTime.unregister(); + this.unregister(); + this.mRemoteTrackTime.unregister(); super.onPause(); } @@ -237,25 +230,25 @@ protected void onPause() { protected void onResume() { super.onResume(); - registerAndLoadStatus(); - mRemoteTrackTime.registerAndLoadStatus(); + this.registerAndLoadStatus(); + this.mRemoteTrackTime.registerAndLoadStatus(); } @Override protected void onDestroy() { - Log.w(TAG, "onDestroy"); + Log.w(MainActivity.TAG, "onDestroy"); try { - unregister(); - mRemoteTrackTime.setTrackTimeListener(null); - mRemoteTrackTime.unregister(); - - mRemoteTrackTime = null; - mTrackReceiver = null; - mStatusReceiver = null; - mPlayingModeReceiver = null; - } catch(Exception ex) { - Log.e(TAG, "", ex); + this.unregister(); + this.mRemoteTrackTime.setTrackTimeListener(null); + this.mRemoteTrackTime.unregister(); + + this.mRemoteTrackTime = null; + this.mTrackReceiver = null; + this.mStatusReceiver = null; + this.mPlayingModeReceiver = null; + } catch(final Exception ex) { + Log.e(MainActivity.TAG, "", ex); } super.onDestroy(); @@ -266,162 +259,162 @@ protected void onDestroy() { * but this approach can be used with a null receiver to get current sticky intent without broadcast receiver. */ private void registerAndLoadStatus() { - mTrackIntent = registerReceiver(mTrackReceiver, new IntentFilter(PowerampAPI.ACTION_TRACK_CHANGED)); - mStatusIntent = registerReceiver(mStatusReceiver, new IntentFilter(PowerampAPI.ACTION_STATUS_CHANGED)); - mPlayingModeIntent = registerReceiver(mPlayingModeReceiver, new IntentFilter(PowerampAPI.ACTION_PLAYING_MODE_CHANGED)); - registerReceiver(mMediaButtonIgnoredReceiver, new IntentFilter(PowerampAPI.ACTION_MEDIA_BUTTON_IGNORED)); + this.mTrackIntent = this.registerReceiver(this.mTrackReceiver, new IntentFilter(PowerampAPI.ACTION_TRACK_CHANGED)); + this.mStatusIntent = this.registerReceiver(this.mStatusReceiver, new IntentFilter(PowerampAPI.ACTION_STATUS_CHANGED)); + this.mPlayingModeIntent = this.registerReceiver(this.mPlayingModeReceiver, new IntentFilter(PowerampAPI.ACTION_PLAYING_MODE_CHANGED)); + this.registerReceiver(this.mMediaButtonIgnoredReceiver, new IntentFilter(PowerampAPI.ACTION_MEDIA_BUTTON_IGNORED)); } private void unregister() { - if(mTrackIntent != null) { + if(null != mTrackIntent) { try { - unregisterReceiver(mTrackReceiver); - } catch(Exception ignored){} // Can throw exception if for some reason broadcast receiver wasn't registered. + this.unregisterReceiver(this.mTrackReceiver); + } catch(final Exception ignored){} // Can throw exception if for some reason broadcast receiver wasn't registered. } - if(mStatusReceiver != null) { + if(null != mStatusReceiver) { try { - unregisterReceiver(mStatusReceiver); - } catch(Exception ignored){} + this.unregisterReceiver(this.mStatusReceiver); + } catch(final Exception ignored){} } - if(mPlayingModeReceiver != null) { + if(null != mPlayingModeReceiver) { try { - unregisterReceiver(mPlayingModeReceiver); - } catch(Exception ignored){} + this.unregisterReceiver(this.mPlayingModeReceiver); + } catch(final Exception ignored){} } - if(mMediaButtonIgnoredReceiver != null) { + if(null != mMediaButtonIgnoredReceiver) { try { - unregisterReceiver(mMediaButtonIgnoredReceiver); - } catch(Exception ignored){} + this.unregisterReceiver(this.mMediaButtonIgnoredReceiver); + } catch(final Exception ignored){} } } private BroadcastReceiver mTrackReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - mTrackIntent = intent; - processTrackIntent(); - if(LOG_VERBOSE) Log.w(TAG, "mTrackReceiver " + intent); + public void onReceive(final Context context, final Intent intent) { + MainActivity.this.mTrackIntent = intent; + MainActivity.this.processTrackIntent(); + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "mTrackReceiver " + intent); } }; private final BroadcastReceiver mMediaButtonIgnoredReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - debugDumpIntent(TAG, "mMediaButtonIgnoredReceiver", intent); - Toast.makeText(MainActivity.this, intent.getAction() + " " + dumpBundle(intent.getExtras()), Toast.LENGTH_SHORT).show(); + public void onReceive(final Context context, final Intent intent) { + MainActivity.debugDumpIntent(MainActivity.TAG, "mMediaButtonIgnoredReceiver", intent); + Toast.makeText(MainActivity.this, intent.getAction() + " " + MainActivity.dumpBundle(intent.getExtras()), Toast.LENGTH_SHORT).show(); } }; void processTrackIntent() { - mCurrentTrack = null; + this.mCurrentTrack = null; - if(mTrackIntent != null) { - mCurrentTrack = mTrackIntent.getBundleExtra(PowerampAPI.EXTRA_TRACK); - if(mCurrentTrack != null) { - int duration = mCurrentTrack.getInt(PowerampAPI.Track.DURATION); - mRemoteTrackTime.updateTrackDuration(duration); // Let RemoteTrackTime know about the current song duration. + if(null != mTrackIntent) { + this.mCurrentTrack = this.mTrackIntent.getBundleExtra(PowerampAPI.EXTRA_TRACK); + if(null != mCurrentTrack) { + final int duration = this.mCurrentTrack.getInt(PowerampAPI.Track.DURATION); + this.mRemoteTrackTime.updateTrackDuration(duration); // Let RemoteTrackTime know about the current song duration. } - int pos = mTrackIntent.getIntExtra(PowerampAPI.Track.POSITION, -1); // Poweramp build-700+ sends position along with the track intent - if(pos != -1) { - mRemoteTrackTime.updateTrackPosition(pos); + final int pos = this.mTrackIntent.getIntExtra(PowerampAPI.Track.POSITION, -1); // Poweramp build-700+ sends position along with the track intent + if(-1 != pos) { + this.mRemoteTrackTime.updateTrackPosition(pos); } - updateTrackUI(); + this.updateTrackUI(); - updateAlbumArt(mCurrentTrack); + this.updateAlbumArt(this.mCurrentTrack); } } private BroadcastReceiver mStatusReceiver = new BroadcastReceiver() { @SuppressWarnings("synthetic-access") @Override - public void onReceive(Context context, Intent intent) { - mStatusIntent = intent; + public void onReceive(final Context context, final Intent intent) { + MainActivity.this.mStatusIntent = intent; - if(LOG_VERBOSE) debugDumpIntent(TAG, "mStatusReceiver", intent); + if(MainActivity.LOG_VERBOSE) MainActivity.debugDumpIntent(MainActivity.TAG, "mStatusReceiver", intent); - updateStatusUI(); + MainActivity.this.updateStatusUI(); } }; private BroadcastReceiver mPlayingModeReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - mPlayingModeIntent = intent; + public void onReceive(final Context context, final Intent intent) { + MainActivity.this.mPlayingModeIntent = intent; - if(LOG_VERBOSE) debugDumpIntent(TAG, "mPlayingModeReceiver", intent); + if(MainActivity.LOG_VERBOSE) MainActivity.debugDumpIntent(MainActivity.TAG, "mPlayingModeReceiver", intent); - updatePlayingModeUI(); + MainActivity.this.updatePlayingModeUI(); } }; // This method updates track related info, album art. @SuppressLint("SetTextI18n") private void updateTrackUI() { - Log.w(TAG, "updateTrackUI"); - - if(mTrackIntent != null) { - if(mCurrentTrack != null) { - ((TextView)findViewById(R.id.cat)).setText(Integer.toString(mCurrentTrack.getInt(PowerampAPI.Track.CAT))); - ((TextView)findViewById(R.id.uri)).setText(mCurrentTrack.getParcelable(PowerampAPI.Track.CAT_URI).toString()); - ((TextView)findViewById(R.id.id)).setText(Long.toString(mCurrentTrack.getLong(PowerampAPI.Track.ID))); - ((TextView)findViewById(R.id.title)).setText(mCurrentTrack.getString(PowerampAPI.Track.TITLE)); - ((TextView)findViewById(R.id.album)).setText(mCurrentTrack.getString(PowerampAPI.Track.ALBUM)); - ((TextView)findViewById(R.id.artist)).setText(mCurrentTrack.getString(PowerampAPI.Track.ARTIST)); - ((TextView)findViewById(R.id.path)).setText(mCurrentTrack.getString(PowerampAPI.Track.PATH)); - - StringBuilder info = new StringBuilder(); - info.append("Codec: ").append(mCurrentTrack.getString(PowerampAPI.Track.CODEC)).append(" "); - info.append("Bitrate: ").append(mCurrentTrack.getInt(PowerampAPI.Track.BITRATE, -1)).append(" "); - info.append("Sample Rate: ").append(mCurrentTrack.getInt(PowerampAPI.Track.SAMPLE_RATE, -1)).append(" "); - info.append("Channels: ").append(mCurrentTrack.getInt(PowerampAPI.Track.CHANNELS, -1)).append(" "); - info.append("Duration: ").append(mCurrentTrack.getInt(PowerampAPI.Track.DURATION, -1)).append("sec "); - - ((TextView)findViewById(R.id.info)).setText(info); + Log.w(MainActivity.TAG, "updateTrackUI"); + + if(null != mTrackIntent) { + if(null != mCurrentTrack) { + ((TextView) this.findViewById(R.id.cat)).setText(Integer.toString(this.mCurrentTrack.getInt(PowerampAPI.Track.CAT))); + ((TextView) this.findViewById(R.id.uri)).setText(this.mCurrentTrack.getParcelable(PowerampAPI.Track.CAT_URI).toString()); + ((TextView) this.findViewById(R.id.id)).setText(Long.toString(this.mCurrentTrack.getLong(PowerampAPI.Track.ID))); + ((TextView) this.findViewById(R.id.title)).setText(this.mCurrentTrack.getString(PowerampAPI.Track.TITLE)); + ((TextView) this.findViewById(R.id.album)).setText(this.mCurrentTrack.getString(PowerampAPI.Track.ALBUM)); + ((TextView) this.findViewById(R.id.artist)).setText(this.mCurrentTrack.getString(PowerampAPI.Track.ARTIST)); + ((TextView) this.findViewById(R.id.path)).setText(this.mCurrentTrack.getString(PowerampAPI.Track.PATH)); + + final StringBuilder info = new StringBuilder(); + info.append("Codec: ").append(this.mCurrentTrack.getString(PowerampAPI.Track.CODEC)).append(" "); + info.append("Bitrate: ").append(this.mCurrentTrack.getInt(PowerampAPI.Track.BITRATE, -1)).append(" "); + info.append("Sample Rate: ").append(this.mCurrentTrack.getInt(PowerampAPI.Track.SAMPLE_RATE, -1)).append(" "); + info.append("Channels: ").append(this.mCurrentTrack.getInt(PowerampAPI.Track.CHANNELS, -1)).append(" "); + info.append("Duration: ").append(this.mCurrentTrack.getInt(PowerampAPI.Track.DURATION, -1)).append("sec "); + + ((TextView) this.findViewById(R.id.info)).setText(info); return; } } // Else clean everything. - ((TextView)findViewById(R.id.info)).setText(""); - ((TextView)findViewById(R.id.title)).setText(""); - ((TextView)findViewById(R.id.album)).setText(""); - ((TextView)findViewById(R.id.artist)).setText(""); - ((TextView)findViewById(R.id.path)).setText(""); + ((TextView) this.findViewById(R.id.info)).setText(""); + ((TextView) this.findViewById(R.id.title)).setText(""); + ((TextView) this.findViewById(R.id.album)).setText(""); + ((TextView) this.findViewById(R.id.artist)).setText(""); + ((TextView) this.findViewById(R.id.path)).setText(""); } void updateStatusUI() { - Log.w(TAG, "updateStatusUI"); - if(mStatusIntent != null) { - boolean paused; + Log.w(MainActivity.TAG, "updateStatusUI"); + if(null != mStatusIntent) { + final boolean paused; - int state = mStatusIntent.getIntExtra(PowerampAPI.EXTRA_STATE, PowerampAPI.STATE_NO_STATE); // NOTE: not used here, provides STATE_* int + final int state = this.mStatusIntent.getIntExtra(PowerampAPI.EXTRA_STATE, PowerampAPI.STATE_NO_STATE); // NOTE: not used here, provides STATE_* int // Each status update can contain track position update as well - int pos = mStatusIntent.getIntExtra(PowerampAPI.Track.POSITION, -1); - if(pos != -1) { - mRemoteTrackTime.updateTrackPosition(pos); + final int pos = this.mStatusIntent.getIntExtra(PowerampAPI.Track.POSITION, -1); + if(-1 != pos) { + this.mRemoteTrackTime.updateTrackPosition(pos); } switch(state) { case PowerampAPI.STATE_PAUSED: paused = true; - startStopRemoteTrackTime(true); + this.startStopRemoteTrackTime(true); break; case PowerampAPI.STATE_PLAYING: paused = false; - startStopRemoteTrackTime(false); + this.startStopRemoteTrackTime(false); break; default: case PowerampAPI.STATE_NO_STATE: case PowerampAPI.STATE_STOPPED: - mRemoteTrackTime.stopSongProgress(); + this.mRemoteTrackTime.stopSongProgress(); paused = true; break; } - ((Button)findViewById(R.id.play)).setText(paused ? ">" : "||"); + ((Button) this.findViewById(R.id.play)).setText(paused ? ">" : "||"); } } @@ -429,10 +422,10 @@ void updateStatusUI() { * Updates shuffle/repeat UI */ void updatePlayingModeUI() { - Log.w(TAG, "updatePlayingModeUI"); - if(mPlayingModeIntent != null) { - int shuffle = mPlayingModeIntent.getIntExtra(PowerampAPI.EXTRA_SHUFFLE, -1); - String shuffleStr; + Log.w(MainActivity.TAG, "updatePlayingModeUI"); + if(null != mPlayingModeIntent) { + final int shuffle = this.mPlayingModeIntent.getIntExtra(PowerampAPI.EXTRA_SHUFFLE, -1); + final String shuffleStr; switch(shuffle) { case PowerampAPI.ShuffleMode.SHUFFLE_ALL: shuffleStr = "Shuffle All"; @@ -450,10 +443,10 @@ void updatePlayingModeUI() { shuffleStr = "Shuffle OFF"; break; } - ((Button)findViewById(R.id.shuffle)).setText(shuffleStr); + ((Button) this.findViewById(R.id.shuffle)).setText(shuffleStr); - int repeat = mPlayingModeIntent.getIntExtra(PowerampAPI.EXTRA_REPEAT, -1); - String repeatStr; + final int repeat = this.mPlayingModeIntent.getIntExtra(PowerampAPI.EXTRA_REPEAT, -1); + final String repeatStr; switch(repeat) { case PowerampAPI.RepeatMode.REPEAT_ON: repeatStr = "Repeat List"; @@ -469,36 +462,36 @@ void updatePlayingModeUI() { break; } - ((Button)findViewById(R.id.repeat)).setText(repeatStr); + ((Button) this.findViewById(R.id.repeat)).setText(repeatStr); } } /** * Commands RemoteTrackTime to start or stop showing the song progress */ - void startStopRemoteTrackTime(boolean paused) { + void startStopRemoteTrackTime(final boolean paused) { if(!paused) { - mRemoteTrackTime.startSongProgress(); + this.mRemoteTrackTime.startSongProgress(); } else { - mRemoteTrackTime.stopSongProgress(); + this.mRemoteTrackTime.stopSongProgress(); } } - @SuppressLint("SetTextI18n") void updateAlbumArt(Bundle track) { - Log.w(TAG, "updateAlbumArt"); + @SuppressLint("SetTextI18n") void updateAlbumArt(final Bundle track) { + Log.w(MainActivity.TAG, "updateAlbumArt"); - ImageView aaImage = findViewById(R.id.album_art); - TextView albumArtInfo = findViewById(R.id.album_art_info); + final ImageView aaImage = this.findViewById(R.id.album_art); + final TextView albumArtInfo = this.findViewById(R.id.album_art_info); - if(track == null) { - Log.w(TAG, "no track"); + if(null == track) { + Log.w(MainActivity.TAG, "no track"); aaImage.setImageBitmap(null); albumArtInfo.setText("no AA"); return; } - Bitmap b = PowerampAPIHelper.getAlbumArt(this, track, 1024, 1024); - if(b != null) { + final Bitmap b = PowerampAPIHelper.getAlbumArt(this, track, 1024, 1024); + if(null != b) { aaImage.setImageBitmap(b); albumArtInfo.setText("scaled w: " + b.getWidth() + " h: " + b.getHeight()); } else { @@ -512,184 +505,184 @@ void startStopRemoteTrackTime(boolean paused) { * Process a button press. Demonstrates sending various commands to Poweramp */ @Override - public void onClick(View v) { - Log.w(TAG, "onClick v=" + v); - int id = v.getId(); + public void onClick(final View v) { + Log.w(MainActivity.TAG, "onClick v=" + v); + final int id = v.getId(); if(id == R.id.play) { - Log.w(TAG, "play"); + Log.w(MainActivity.TAG, "play"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.TOGGLE_PLAY_PAUSE), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.pause) { - Log.w(TAG, "pause"); + Log.w(MainActivity.TAG, "pause"); // NOTE: since 867. Sending String command instead of int - PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, "PAUSE"), FORCE_API_ACTIVITY); + PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, "PAUSE"), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.prev) { - Log.w(TAG, "prev"); + Log.w(MainActivity.TAG, "prev"); // NOTE: since 867. Sending lowcase String command instead of int - PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, "previous"), FORCE_API_ACTIVITY); + PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, "previous"), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.next) { - Log.w(TAG, "next"); + Log.w(MainActivity.TAG, "next"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.NEXT), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.prev_in_cat) { - Log.w(TAG, "prev_in_cat"); + Log.w(MainActivity.TAG, "prev_in_cat"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.PREVIOUS_IN_CAT), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.next_in_cat) { - Log.w(TAG, "next_in_cat"); + Log.w(MainActivity.TAG, "next_in_cat"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.NEXT_IN_CAT), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.repeat) { - Log.w(TAG, "repeat"); + Log.w(MainActivity.TAG, "repeat"); // No toast for this button just for demo. PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.REPEAT), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.shuffle) { - Log.w(TAG, "shuffle"); + Log.w(MainActivity.TAG, "shuffle"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SHUFFLE), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.repeat_all) { - Log.w(TAG, "repeat_all"); + Log.w(MainActivity.TAG, "repeat_all"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.REPEAT) - .putExtra(PowerampAPI.EXTRA_REPEAT, PowerampAPI.RepeatMode.REPEAT_ON), FORCE_API_ACTIVITY); + .putExtra(PowerampAPI.EXTRA_REPEAT, PowerampAPI.RepeatMode.REPEAT_ON), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.repeat_off) { - Log.w(TAG, "repeat_off"); + Log.w(MainActivity.TAG, "repeat_off"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.REPEAT) - .putExtra(PowerampAPI.EXTRA_REPEAT, PowerampAPI.RepeatMode.REPEAT_NONE), FORCE_API_ACTIVITY); + .putExtra(PowerampAPI.EXTRA_REPEAT, PowerampAPI.RepeatMode.REPEAT_NONE), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.shuffle_all) { - Log.w(TAG, "shuffle_all"); + Log.w(MainActivity.TAG, "shuffle_all"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SHUFFLE) - .putExtra(PowerampAPI.EXTRA_SHUFFLE, PowerampAPI.ShuffleMode.SHUFFLE_ALL), FORCE_API_ACTIVITY); + .putExtra(PowerampAPI.EXTRA_SHUFFLE, PowerampAPI.ShuffleMode.SHUFFLE_ALL), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.shuffle_off) { - Log.w(TAG, "shuffle_all"); + Log.w(MainActivity.TAG, "shuffle_all"); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SHUFFLE) - .putExtra(PowerampAPI.EXTRA_SHUFFLE, PowerampAPI.ShuffleMode.SHUFFLE_NONE), FORCE_API_ACTIVITY); + .putExtra(PowerampAPI.EXTRA_SHUFFLE, PowerampAPI.ShuffleMode.SHUFFLE_NONE), MainActivity.FORCE_API_ACTIVITY); } else if(id == R.id.commit_eq) { - Log.w(TAG, "commit_eq"); - commitEq(); + Log.w(MainActivity.TAG, "commit_eq"); + this.commitEq(); } else if(id == R.id.play_file) { - Log.w(TAG, "play_file"); + Log.w(MainActivity.TAG, "play_file"); try { - String uri = ((TextView) findViewById(R.id.play_file_path)).getText().toString(); + final String uri = ((TextView) this.findViewById(R.id.play_file_path)).getText().toString(); if(uri.length() > "content://".length()) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.OPEN_TO_PLAY) //.putExtra(PowerampAPI.Track.POSITION, 10) // Play from 10th second. - .setData(Uri.parse(uri)), FORCE_API_ACTIVITY); + .setData(Uri.parse(uri)), MainActivity.FORCE_API_ACTIVITY); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(MainActivity.TAG, "", th); Toast.makeText(this, th.getMessage(), Toast.LENGTH_LONG).show(); } } else if(id == R.id.folders) { - startActivitySafe(new Intent(this, FoldersActivity.class)); + this.startActivitySafe(new Intent(this, FoldersActivity.class)); } else if(id == R.id.play_album) { - playAlbum(); + this.playAlbum(); } else if(id == R.id.play_all_songs) { - playAllSongs(); + this.playAllSongs(); } else if(id == R.id.play_second_artist_first_album) { - playSecondArtistFirstAlbum(); + this.playSecondArtistFirstAlbum(); } else if(id == R.id.eq) { - startActivitySafe(new Intent(this, EqActivity.class)); + this.startActivitySafe(new Intent(this, EqActivity.class)); } else if(id == R.id.pa_current_list) { - startActivitySafe(new Intent(PowerampAPI.ACTION_SHOW_CURRENT)); + this.startActivitySafe(new Intent(PowerampAPI.ACTION_SHOW_CURRENT)); } else if(id == R.id.pa_folders) { - startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").build())); + this.startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("folders").build())); } else if(id == R.id.pa_all_songs) { - startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build())); + this.startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build())); } else if(id == R.id.create_playlist) { - createPlaylistAndAddToIt(); + this.createPlaylistAndAddToIt(); } else if(id == R.id.create_playlist_w_streams) { - createPlaylistWStreams(); + this.createPlaylistWStreams(); } else if(id == R.id.goto_created_playlist) { - gotoCreatedPlaylist(); + this.gotoCreatedPlaylist(); } else if(id == R.id.add_to_q_and_goto_q) { - addToQAndGotoQ(); + this.addToQAndGotoQ(); } else if(id == R.id.queue) { - startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("queue").build())); + this.startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("queue").build())); } else if(id == R.id.get_all_prefs) { - getAllPrefs(); + this.getAllPrefs(); } else if(id == R.id.get_pref) { - getPref(); + this.getPref(); } } - private void startActivitySafe(@NonNull Intent intent) { + private void startActivitySafe(@NonNull final Intent intent) { try { - startActivity(intent); - } catch(Throwable th) { - Log.e(TAG, "FAIL intent=" + intent, th); + this.startActivity(intent); + } catch(final Throwable th) { + Log.e(MainActivity.TAG, "FAIL intent=" + intent, th); } } - public void openNowPlayingTracks(View view) { - if(mCurrentTrack != null) { - Uri catUri = mCurrentTrack.getParcelable(PowerampAPI.Track.CAT_URI); - if(catUri != null) { + public void openNowPlayingTracks(final View view) { + if(null != mCurrentTrack) { + final Uri catUri = this.mCurrentTrack.getParcelable(PowerampAPI.Track.CAT_URI); + if(null != catUri) { // NOTE: Poweramp may include query parameters such as shs=[SHUFFLE MODE], etc. into the CAT_URI // To avoid shuffled and otherwise modified list, we're clearing query parameters here - Uri uri = catUri.buildUpon().clearQuery().build(); + final Uri uri = catUri.buildUpon().clearQuery().build(); - Log.w(TAG, "openNowPlayingTracks catUri=" + catUri + " uri=>" + uri); + Log.w(MainActivity.TAG, "openNowPlayingTracks catUri=" + catUri + " uri=>" + uri); - startActivitySafe(new Intent(this, TrackListActivity.class).setData(uri)); + this.startActivitySafe(new Intent(this, TrackListActivity.class).setData(uri)); return; // Done here } } Toast.makeText(this, "No current category available", Toast.LENGTH_SHORT).show(); } - public void seekBackward10s(View view) { + public void seekBackward10s(final View view) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SEEK) .putExtra(PowerampAPI.EXTRA_RELATIVE_POSITION, -10) .putExtra(PowerampAPI.EXTRA_LOCK, true) // If EXTRA_LOCK=true, we don't change track by seeking past start/end , - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } - public void seekForward10s(View view) { + public void seekForward10s(final View view) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SEEK) .putExtra(PowerampAPI.EXTRA_RELATIVE_POSITION, 10) .putExtra(PowerampAPI.EXTRA_LOCK, true) // If EXTRA_LOCK=true, we don't change track by seeking past start/end , - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } - public void exportPrefs(View view) { + public void exportPrefs(final View view) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.Settings.ACTION_EXPORT_SETTINGS) .putExtra(PowerampAPI.Settings.EXTRA_UI, true) - , FORCE_API_ACTIVITY); + , MainActivity.FORCE_API_ACTIVITY); } - public void importPrefs(View view) { + public void importPrefs(final View view) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.Settings.ACTION_IMPORT_SETTINGS) .putExtra(PowerampAPI.Settings.EXTRA_UI, true) - , FORCE_API_ACTIVITY); + , MainActivity.FORCE_API_ACTIVITY); } /** Get the specified preference and show its name, type, value */ @SuppressLint("SetTextI18n") private void getPref() { - EditText prefET = findViewById(R.id.pref); - String prefName = prefET.getText().toString(); - TextView prefsTV = findViewById(R.id.prefs); + final EditText prefET = this.findViewById(R.id.pref); + final String prefName = prefET.getText().toString(); + final TextView prefsTV = this.findViewById(R.id.prefs); - if(prefName.length() > 0) { - Bundle bundle = new Bundle(); + if(0 < prefName.length()) { + final Bundle bundle = new Bundle(); bundle.putString(prefName, null); Bundle resultPrefs = null; try { - resultPrefs = getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_PREFERENCE, null, bundle); - } catch(IllegalArgumentException ex) { - Log.e(TAG, "FAIL Poweramp not installed", ex); + resultPrefs = this.getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_PREFERENCE, null, bundle); + } catch(final IllegalArgumentException ex) { + Log.e(MainActivity.TAG, "FAIL Poweramp not installed", ex); } - if(resultPrefs != null) { + if(null != resultPrefs) { - Object value = resultPrefs.get(prefName); - if(value != null) { + final Object value = resultPrefs.get(prefName); + if(null != value) { prefsTV.setText(prefName + " (" + value.getClass().getSimpleName() + "): " + value); prefsTV.setBackground(null); } else { @@ -706,21 +699,21 @@ public void importPrefs(View view) { /** Get all available preferences and dump the resulting bundle */ private void getAllPrefs() { - TextView prefsTV = findViewById(R.id.prefs); + final TextView prefsTV = this.findViewById(R.id.prefs); try { - Bundle resultPrefs = getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_PREFERENCE, null, null); + final Bundle resultPrefs = this.getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_PREFERENCE, null, null); - prefsTV.setText(dumpBundle(resultPrefs)); + prefsTV.setText(MainActivity.dumpBundle(resultPrefs)); prefsTV.getParent().requestChildFocus(prefsTV, prefsTV); - } catch(IllegalArgumentException ex) { - Log.e(TAG, "FAIL Poweramp not installed", ex); + } catch(final IllegalArgumentException ex) { + Log.e(MainActivity.TAG, "FAIL Poweramp not installed", ex); } } - public void setPref(View view) { - EditText pref = findViewById(R.id.pref); - String name = pref.getText().toString().trim(); + public void setPref(final View view) { + final EditText pref = this.findViewById(R.id.pref); + final String name = pref.getText().toString().trim(); if(TextUtils.isEmpty(name)) { pref.setError("Empty"); return; @@ -728,10 +721,10 @@ public void setPref(View view) { pref.setError(null); - EditText prefValue = findViewById(R.id.pref_value); - String value = prefValue.getText().toString().trim(); + final EditText prefValue = this.findViewById(R.id.pref_value); + final String value = prefValue.getText().toString().trim(); - Bundle request = new Bundle(); + final Bundle request = new Bundle(); prefValue.setError(null); boolean failed = false; // Guess the type from the value @@ -743,30 +736,30 @@ public void setPref(View view) { request.putBoolean(name, false); } else { try { - int intValue = Integer.parseInt(value); + final int intValue = Integer.parseInt(value); // We are able to parse this as int, though preference can be any type. // Real code should decide the type based on existing knowledge of the preference type, which don't have here request.putInt(name, intValue); - } catch(NumberFormatException ex) { + } catch(final NumberFormatException ex) { try { - float intValue = Float.parseFloat(value); + final float intValue = Float.parseFloat(value); // We are able to parse this as float, though actual preference can by any type. // Real code should decide the type based on existing knowledge of the preference type, which don't have here request.putFloat(name, intValue); - } catch(NumberFormatException ex2) { + } catch(final NumberFormatException ex2) { prefValue.setError("Failed to guess type"); failed = true; } } } if(!failed) { - TextView prefsTV = findViewById(R.id.prefs); + final TextView prefsTV = this.findViewById(R.id.prefs); // OK, let's call it - Bundle resultPrefs = getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_SET_PREFERENCE, null, request); + final Bundle resultPrefs = this.getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_SET_PREFERENCE, null, request); - prefsTV.setText(dumpBundle(resultPrefs)); + prefsTV.setText(MainActivity.dumpBundle(resultPrefs)); prefsTV.getParent().requestChildFocus(prefsTV, prefsTV); } } @@ -775,21 +768,21 @@ public void setPref(View view) { * Process some long presses */ @Override - public boolean onLongClick(View v) { - int id = v.getId(); + public boolean onLongClick(final View v) { + final int id = v.getId(); if(id == R.id.play) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.STOP), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); return true; } else if(id == R.id.next) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.BEGIN_FAST_FORWARD), - FORCE_API_ACTIVITY); - mProcessingLongPress = true; + MainActivity.FORCE_API_ACTIVITY); + this.mProcessingLongPress = true; return true; } else if(id == R.id.prev) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.BEGIN_REWIND), - FORCE_API_ACTIVITY); - mProcessingLongPress = true; + MainActivity.FORCE_API_ACTIVITY); + this.mProcessingLongPress = true; return true; } @@ -801,24 +794,24 @@ public boolean onLongClick(View v) { */ @SuppressLint("ClickableViewAccessibility") @Override - public boolean onTouch(View v, MotionEvent event) { + public boolean onTouch(final View v, final MotionEvent event) { switch(event.getActionMasked()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { - int id = v.getId(); + final int id = v.getId(); if(id == R.id.next) { - Log.e(TAG, "onTouch next ACTION_UP"); - if(mProcessingLongPress) { + Log.e(MainActivity.TAG, "onTouch next ACTION_UP"); + if(this.mProcessingLongPress) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, - PowerampAPI.Commands.END_FAST_FORWARD), FORCE_API_ACTIVITY); - mProcessingLongPress = false; + PowerampAPI.Commands.END_FAST_FORWARD), MainActivity.FORCE_API_ACTIVITY); + this.mProcessingLongPress = false; } return false; } else if(id == R.id.prev) { - if(mProcessingLongPress) { + if(this.mProcessingLongPress) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND).putExtra(PowerampAPI.EXTRA_COMMAND, - PowerampAPI.Commands.END_REWIND), FORCE_API_ACTIVITY); - mProcessingLongPress = false; + PowerampAPI.Commands.END_REWIND), MainActivity.FORCE_API_ACTIVITY); + this.mProcessingLongPress = false; } return false; } @@ -835,18 +828,18 @@ private void playAllSongs() { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.OPEN_TO_PLAY) .setData(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build()), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } /** * Get first album id and play it */ private void playAlbum() { - Cursor c = getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("albums").build(), new String[]{ "albums._id", "album" }, null, null, "album"); - if(c != null) { + final Cursor c = this.getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("albums").build(), new String[]{ "albums._id", "album" }, null, null, "album"); + if(null != c) { if(c.moveToNext()) { - long albumId = c.getLong(0); - String name = c.getString(1); + final long albumId = c.getLong(0); + final String name = c.getString(1); Toast.makeText(this, "Playing album: " + name, Toast.LENGTH_SHORT).show(); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) @@ -856,7 +849,7 @@ private void playAlbum() { .appendEncodedPath(Long.toString(albumId)) .appendEncodedPath("files") .build()), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } c.close(); } @@ -867,21 +860,21 @@ private void playAlbum() { */ private void playSecondArtistFirstAlbum() { // Get first artist. - Cursor c = getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("artists").build(), + final Cursor c = this.getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("artists").build(), new String[]{ "artists._id", "artist" }, null, null, "artist_sort COLLATE NOCASE"); - if(c != null) { + if(null != c) { c.moveToNext(); // First artist. if(c.moveToNext()) { // Second artist. - long artistId = c.getLong(0); - String artist = c.getString(1); - Cursor c2 = getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("artists_albums").build(), + final long artistId = c.getLong(0); + final String artist = c.getString(1); + final Cursor c2 = this.getContentResolver().query(PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("artists_albums").build(), new String[] { "albums._id", "album" }, "artists._id=?", new String[]{ Long.toString(artistId) }, "album_sort COLLATE NOCASE"); - if(c2 != null) { + if(null != c2) { if(c2.moveToNext()) { - long albumId = c2.getLong(0); - String album = c2.getString(1); + final long albumId = c2.getLong(0); + final String album = c2.getString(1); Toast.makeText(this, "Playing artist: " + artist + " album: " + album, Toast.LENGTH_SHORT).show(); @@ -894,7 +887,7 @@ private void playSecondArtistFirstAlbum() { .appendEncodedPath(Long.toString(albumId)) .appendEncodedPath("files") .build() - ), FORCE_API_ACTIVITY); + ), MainActivity.FORCE_API_ACTIVITY); } c2.close(); } @@ -909,40 +902,40 @@ private void playSecondArtistFirstAlbum() { * Event handler for Dynamic Eq checkbox */ @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - findViewById(R.id.commit_eq).setEnabled(!isChecked); + public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { + this.findViewById(R.id.commit_eq).setEnabled(!isChecked); } /** * Generates and sends presetString to Poweramp Eq */ private void commitEq() { - StringBuilder presetString = new StringBuilder(); - - TableLayout equLayout = findViewById(R.id.equ_layout); - int count = equLayout.getChildCount(); - for(int i = count - 1; i >= 0; i--) { - SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); - String name = (String)bar.getTag(); - float value = seekBarToValue(name, bar.getProgress()); + final StringBuilder presetString = new StringBuilder(); + + final TableLayout equLayout = this.findViewById(R.id.equ_layout); + final int count = equLayout.getChildCount(); + for(int i = count - 1; 0 <= i; i--) { + final SeekBar bar = (SeekBar)((ViewGroup)equLayout.getChildAt(i)).getChildAt(1); + final String name = (String)bar.getTag(); + final float value = this.seekBarToValue(name, bar.getProgress()); presetString.append(name).append("=").append(value).append(";"); } PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_STRING) .putExtra(PowerampAPI.EXTRA_VALUE, presetString.toString()), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } /** * Applies correct seekBar-to-float scaling */ - private float seekBarToValue(String name, int progress) { - float value; + private float seekBarToValue(final String name, final int progress) { + final float value; if("preamp".equals(name) || "bass".equals(name) || "treble".equals(name)) { - value = progress / 100.f; + value = progress / 100.0f; } else { - value = (progress - 100) / 100.f; + value = (progress - 100) / 100.0f; } return value; } @@ -951,51 +944,51 @@ private float seekBarToValue(String name, int progress) { * Event handler for both song progress seekbar and equalizer bands */ @Override - public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) { - int id = bar.getId(); + public void onProgressChanged(final SeekBar bar, final int progress, final boolean fromUser) { + final int id = bar.getId(); if(id == R.id.song_seekbar) { if(fromUser) { - sendSeek(false); + this.sendSeek(false); } } else if(id == R.id.sleep_timer_seekbar) { - updateSleepTimer(progress); + this.updateSleepTimer(progress); } } @Override - public void onStartTrackingTouch(SeekBar seekBar) { + public void onStartTrackingTouch(final SeekBar seekBar) { } /** * Force seek when user ends seeking */ @Override - public void onStopTrackingTouch(SeekBar seekBar) { - sendSeek(true); + public void onStopTrackingTouch(final SeekBar seekBar) { + this.sendSeek(true); } /** * Send a seek command */ - private void sendSeek(boolean ignoreThrottling) { + private void sendSeek(final boolean ignoreThrottling) { - int position = mSongSeekBar.getProgress(); - mRemoteTrackTime.updateTrackPosition(position); + final int position = this.mSongSeekBar.getProgress(); + this.mRemoteTrackTime.updateTrackPosition(position); // Apply some throttling to avoid too many intents to be generated. - if((mLastSeekSentTime == 0 || System.currentTimeMillis() - mLastSeekSentTime > SEEK_THROTTLE) - || ignoreThrottling && mLastSentSeekPosition != position // Do not send same position for cases like quick seekbar touch + if((0 == mLastSeekSentTime || SEEK_THROTTLE < System.currentTimeMillis() - mLastSeekSentTime) + || ignoreThrottling && this.mLastSentSeekPosition != position // Do not send same position for cases like quick seekbar touch ) { - mLastSeekSentTime = System.currentTimeMillis(); + this.mLastSeekSentTime = System.currentTimeMillis(); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SEEK) .putExtra(PowerampAPI.Track.POSITION, position), - FORCE_API_ACTIVITY); - mLastSentSeekPosition = position; - Log.w(TAG, "sendSeek sent position=" + position); + MainActivity.FORCE_API_ACTIVITY); + this.mLastSentSeekPosition = position; + Log.w(MainActivity.TAG, "sendSeek sent position=" + position); } else { - Log.w(TAG, "sendSeek throttled"); + Log.w(MainActivity.TAG, "sendSeek throttled"); } } @@ -1004,117 +997,117 @@ private void sendSeek(boolean ignoreThrottling) { * Event handler for Presets spinner */ @Override - public void onItemSelected(AdapterView adapter, View item, int pos, long id) { - if(!mSettingPreset) { + public void onItemSelected(final AdapterView adapter, final View item, final int pos, final long id) { + if(!this.mSettingPreset) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_EQU_PRESET) .putExtra(PowerampAPI.EXTRA_ID, id), - FORCE_API_ACTIVITY); + MainActivity.FORCE_API_ACTIVITY); } else { - mSettingPreset = false; + this.mSettingPreset = false; } } @Override - public void onNothingSelected(AdapterView arg0) { + public void onNothingSelected(final AdapterView arg0) { } /** * Callback from RemoteTrackTime. Updates durations (both seekbar max value and duration label) */ @Override - public void onTrackDurationChanged(int duration) { - mDurationBuffer.setLength(0); + public void onTrackDurationChanged(final int duration) { + this.mDurationBuffer.setLength(0); - formatTimeS(mDurationBuffer, duration, true); + MainActivity.formatTimeS(this.mDurationBuffer, duration, true); - mDuration.setText(mDurationBuffer); + this.mDuration.setText(this.mDurationBuffer); - mSongSeekBar.setMax(duration); + this.mSongSeekBar.setMax(duration); } /** * Callback from RemoteTrackTime. Updates the current song progress. Ensures extra event is not processed (mUpdatingSongSeekBar). */ @Override - public void onTrackPositionChanged(int position) { - mElapsedBuffer.setLength(0); + public void onTrackPositionChanged(final int position) { + this.mElapsedBuffer.setLength(0); - formatTimeS(mElapsedBuffer, position, false); + MainActivity.formatTimeS(this.mElapsedBuffer, position, false); - mElapsed.setText(mElapsedBuffer); + this.mElapsed.setText(this.mElapsedBuffer); - if(mSongSeekBar.isPressed()) { + if(this.mSongSeekBar.isPressed()) { return; } - mSongSeekBar.setProgress(position); + this.mSongSeekBar.setProgress(position); } - public void setSleepTimer(View view) { + public void setSleepTimer(final View view) { PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SLEEP_TIMER) - .putExtra(PowerampAPI.EXTRA_SECONDS, ((SeekBar)findViewById(R.id.sleep_timer_seekbar)).getProgress()) - .putExtra(PowerampAPI.EXTRA_PLAY_TO_END, ((CheckBox)findViewById(R.id.sleep_timer_play_to_end)).isChecked()), - FORCE_API_ACTIVITY); + .putExtra(PowerampAPI.EXTRA_SECONDS, ((SeekBar) this.findViewById(R.id.sleep_timer_seekbar)).getProgress()) + .putExtra(PowerampAPI.EXTRA_PLAY_TO_END, ((CheckBox) this.findViewById(R.id.sleep_timer_play_to_end)).isChecked()), + MainActivity.FORCE_API_ACTIVITY); } - public void rescan(View view) { - var componentName = PowerampAPIHelper.getScannerServiceComponentName(this); - if(componentName == null) { - Log.e(TAG, "FAIL !componentName"); + public void rescan(final View view) { + final var componentName = PowerampAPIHelper.getScannerServiceComponentName(this); + if(null == componentName) { + Log.e(MainActivity.TAG, "FAIL !componentName"); return; } - Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) + final Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) .setComponent(componentName) - .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, getPackageName() + " user requested"); - startService(intent); + .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, this.getPackageName() + " user requested"); + this.startService(intent); } - public void milkRescan(View view) { - final int powerampBuild = PowerampAPIHelper.getPowerampBuild(this); - if(powerampBuild <= 0) { - Log.e(TAG, "FAIL !powerampBuild"); + public void milkRescan(final View view) { + int powerampBuild = PowerampAPIHelper.getPowerampBuild(this); + if(0 >= powerampBuild) { + Log.e(MainActivity.TAG, "FAIL !powerampBuild"); return; } - Intent intent = new Intent(PowerampAPI.MilkScanner.ACTION_SCAN) - .putExtra(PowerampAPI.MilkScanner.EXTRA_CAUSE, getPackageName() + " user requested"); + final Intent intent = new Intent(PowerampAPI.MilkScanner.ACTION_SCAN) + .putExtra(PowerampAPI.MilkScanner.EXTRA_CAUSE, this.getPackageName() + " user requested"); - if(powerampBuild >= 868) { + if(868 <= powerampBuild) { - PowerampAPIHelper.sendPAIntent(this, intent, FORCE_API_ACTIVITY); // Since 868 + PowerampAPIHelper.sendPAIntent(this, intent, MainActivity.FORCE_API_ACTIVITY); // Since 868 } else { - final ComponentName milkScannerServiceComponentName = PowerampAPIHelper.getMilkScannerServiceComponentName(this); + ComponentName milkScannerServiceComponentName = PowerampAPIHelper.getMilkScannerServiceComponentName(this); intent.setComponent(milkScannerServiceComponentName); // Used prior build 868 - startService(intent); + this.startService(intent); } } // ================================================= - @SuppressLint("SetTextI18n") private void updateSleepTimer(int progress) { - ((TextView)findViewById(R.id.sleep_timer_value)).setText("Seep in " + progress + "s"); + @SuppressLint("SetTextI18n") private void updateSleepTimer(final int progress) { + ((TextView) this.findViewById(R.id.sleep_timer_value)).setText("Seep in " + progress + "s"); } /** Retrieves Poweramp build number and normalizes it to ### form, e.g. 846002 => 846 */ private int getPowerampBuildNumber() { - int code = mPowerampBuildNumber; - if(code == 0) { + int code = this.mPowerampBuildNumber; + if(0 == code) { try { - code = getPackageManager().getPackageInfo(PowerampAPIHelper.getPowerampPackageName(this), 0).versionCode; - } catch(PackageManager.NameNotFoundException ex) { + code = this.getPackageManager().getPackageInfo(PowerampAPIHelper.getPowerampPackageName(this), 0).versionCode; + } catch(final PackageManager.NameNotFoundException ex) { // code==0 here - Log.e(TAG, "", ex); + Log.e(MainActivity.TAG, "", ex); } - if(code > 1000) { + if(1000 < code) { code = code / 1000; } - mPowerampBuildNumber = code; + this.mPowerampBuildNumber = code; } return code; } @@ -1124,66 +1117,66 @@ private int getPowerampBuildNumber() { * NOTE: real code should run on some worker thread */ private void createPlaylistAndAddToIt() { - int buildNumber = getPowerampBuildNumber(); - if(buildNumber == 0) { - Log.e(TAG, "createPlaylistAndAddToIt FAIL !buildNumber"); + final int buildNumber = this.getPowerampBuildNumber(); + if(0 == buildNumber) { + Log.e(MainActivity.TAG, "createPlaylistAndAddToIt FAIL !buildNumber"); return; } - ContentResolver cr = getContentResolver(); - Uri playlistsUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("playlists").build(); + final ContentResolver cr = this.getContentResolver(); + final Uri playlistsUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("playlists").build(); // NOTE: we need raw column names for an insert query (without table name), thus using getRawColName() - ContentValues values = new ContentValues(); - values.put(getRawColName(TableDefs.Playlists.PLAYLIST), "Sample Playlist " + System.currentTimeMillis()); - Uri playlistInsertedUri = cr.insert(playlistsUri, values); + final ContentValues values = new ContentValues(); + values.put(MainActivity.getRawColName(TableDefs.Playlists.PLAYLIST), "Sample Playlist " + System.currentTimeMillis()); + final Uri playlistInsertedUri = cr.insert(playlistsUri, values); - if(playlistInsertedUri != null) { - Log.w(TAG, "createPlaylistAndAddToIt inserted=" + playlistInsertedUri); + if(null != playlistInsertedUri) { + Log.w(MainActivity.TAG, "createPlaylistAndAddToIt inserted=" + playlistInsertedUri); // NOTE: we are inserting into /playlists/#/files, playlistInsertedUri (/playlists/#) is not valid for entries insertion - Uri playlistEntriesUri = playlistInsertedUri.buildUpon().appendEncodedPath("files").build(); + final Uri playlistEntriesUri = playlistInsertedUri.buildUpon().appendEncodedPath("files").build(); - mLastCreatedPlaylistFilesUri = playlistEntriesUri; + this.mLastCreatedPlaylistFilesUri = playlistEntriesUri; // Select up to 10 random files final int numFilesToInsert = 10; - Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build(); - Cursor c = getContentResolver().query(filesUri, new String[]{ TableDefs.Files._ID, TableDefs.Files.NAME, TableDefs.Folders.PATH }, null, null, + final Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build(); + final Cursor c = this.getContentResolver().query(filesUri, new String[]{ TableDefs.Files._ID, TableDefs.Files.NAME, TableDefs.Folders.PATH }, null, null, "RANDOM() LIMIT " + numFilesToInsert); int sort = 0; - if(c != null) { + if(null != c) { while(c.moveToNext()) { - long fileId = c.getLong(0); - String fileName = c.getString(1); - String folderPath = c.getString(2); + final long fileId = c.getLong(0); + final String fileName = c.getString(1); + final String folderPath = c.getString(2); values.clear(); - values.put(getRawColName(TableDefs.PlaylistEntries.FOLDER_FILE_ID), fileId); + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.FOLDER_FILE_ID), fileId); // Playlist behavior changed in Poweramp build 842 - now each playlist entry should contain full path // This restriction was uplifted in build 846, but anyway, it's preferable to fill playlist entry folder_path and file_name columns to allow // easy resolution of playlist entries in case user changes music folders, storage, etc. - if(buildNumber >= 842) { - values.put(getRawColName(TableDefs.PlaylistEntries.FOLDER_PATH), folderPath); - values.put(getRawColName(TableDefs.PlaylistEntries.FILE_NAME), fileName); + if(842 <= buildNumber) { + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.FOLDER_PATH), folderPath); + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.FILE_NAME), fileName); } // Playlist entries are always sorted by "sort" fields, so if we want them to be in order, we should provide it. // If we're adding entries to existing playlist, it's a good idea to get MAX(sort) first from the given playlist - values.put(getRawColName(TableDefs.PlaylistEntries.SORT), sort); + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.SORT), sort); - Uri entryUri = cr.insert(playlistEntriesUri, values); - if(entryUri != null) { - Log.w(TAG, "createPlaylistAndAddToIt inserted entry fileId=" + fileId + " sort=" + sort + " folderPath=" + folderPath + " fileName=" + fileName + + final Uri entryUri = cr.insert(playlistEntriesUri, values); + if(null != entryUri) { + Log.w(MainActivity.TAG, "createPlaylistAndAddToIt inserted entry fileId=" + fileId + " sort=" + sort + " folderPath=" + folderPath + " fileName=" + fileName + " entryUri=" + entryUri); sort++; } else { - Log.e(TAG, "createPlaylistAndAddToIt FAILED to insert entry fileId=" + fileId); + Log.e(MainActivity.TAG, "createPlaylistAndAddToIt FAILED to insert entry fileId=" + fileId); } } @@ -1192,26 +1185,26 @@ private void createPlaylistAndAddToIt() { Toast.makeText(this, "Inserted files=" + sort, Toast.LENGTH_SHORT).show(); } - if(sort > 0) { + if(0 < sort) { // Force Poweramp to reload data in UI / PlayerService as we changed something - Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); + final Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); intent.setPackage(PowerampAPIHelper.getPowerampPackageName(this)); - intent.putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); + intent.putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); // NOTE: important to send the changed table for an adequate UI / PlayerService reloading intent.putExtra(PowerampAPI.EXTRA_TABLE, TableDefs.PlaylistEntries.TABLE); - if(FORCE_API_ACTIVITY) { + if(MainActivity.FORCE_API_ACTIVITY) { intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); - startActivitySafe(intent); + this.startActivitySafe(intent); } else { - sendBroadcast(intent); + this.sendBroadcast(intent); } } // Make open playlist button active - findViewById(R.id.goto_created_playlist).setEnabled(true); + this.findViewById(R.id.goto_created_playlist).setEnabled(true); } else { - Log.e(TAG, "createPlaylistAndAddToIt FAILED"); + Log.e(MainActivity.TAG, "createPlaylistAndAddToIt FAILED"); } } @@ -1220,80 +1213,80 @@ private void createPlaylistAndAddToIt() { * NOTE: real code should run on some worker thread */ private void createPlaylistWStreams() { - int buildNumber = getPowerampBuildNumber(); + final int buildNumber = this.getPowerampBuildNumber(); // We need at least 842 build - if(buildNumber < 842) { + if(842 > buildNumber) { Toast.makeText(this, "Poweramp build is too old", Toast.LENGTH_SHORT).show(); return; } - ContentResolver cr = getContentResolver(); - Uri playlistsUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("playlists").build(); + final ContentResolver cr = this.getContentResolver(); + final Uri playlistsUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("playlists").build(); // NOTE: we need raw column names for an insert query (without table name), thus using getRawColName() // NOTE: playlist with a stream doesn't differ from other (track based) playlists. Only playlist entries differ vs usual file tracks - String playlistName = "Stream Playlist " + System.currentTimeMillis(); - ContentValues values = new ContentValues(); - values.put(getRawColName(TableDefs.Playlists.PLAYLIST), playlistName); - Uri playlistInsertedUri = cr.insert(playlistsUri, values); + final String playlistName = "Stream Playlist " + System.currentTimeMillis(); + final ContentValues values = new ContentValues(); + values.put(MainActivity.getRawColName(TableDefs.Playlists.PLAYLIST), playlistName); + final Uri playlistInsertedUri = cr.insert(playlistsUri, values); - if(playlistInsertedUri == null) { + if(null == playlistInsertedUri) { Toast.makeText(this, "Failed to create playlist", Toast.LENGTH_SHORT).show(); return; } - Log.w(TAG, "createPlaylistAndAddToIt inserted=" + playlistInsertedUri); + Log.w(MainActivity.TAG, "createPlaylistAndAddToIt inserted=" + playlistInsertedUri); // NOTE: we are inserting into /playlists/#/files, playlistInsertedUri (/playlists/#) is not valid for the entries insertion - Uri playlistEntriesUri = playlistInsertedUri.buildUpon().appendEncodedPath("files").build(); - mLastCreatedPlaylistFilesUri = playlistEntriesUri; + final Uri playlistEntriesUri = playlistInsertedUri.buildUpon().appendEncodedPath("files").build(); + this.mLastCreatedPlaylistFilesUri = playlistEntriesUri; // To create stream entry, we just provide the url. Entry is added as the last one values.clear(); - values.put(getRawColName(TableDefs.PlaylistEntries.FILE_NAME), "http://64.71.77.150:8000/stream"); - Uri entryUri1 = cr.insert(playlistEntriesUri, values); + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.FILE_NAME), "http://64.71.77.150:8000/stream"); + final Uri entryUri1 = cr.insert(playlistEntriesUri, values); values.clear(); - values.put(getRawColName(TableDefs.PlaylistEntries.FILE_NAME), "http://94.23.205.82:5726/;stream/1"); - Uri entryUri2 = cr.insert(playlistEntriesUri, values); + values.put(MainActivity.getRawColName(TableDefs.PlaylistEntries.FILE_NAME), "http://94.23.205.82:5726/;stream/1"); + final Uri entryUri2 = cr.insert(playlistEntriesUri, values); - if(entryUri1 != null && entryUri2 != null) { + if(null != entryUri1 && null != entryUri2) { Toast.makeText(this, "Inserted streams OK, playlist=" + playlistName, Toast.LENGTH_SHORT).show(); // Force Poweramp to reload data in UI / PlayerService as we changed something - Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); + final Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); intent.setPackage(PowerampAPIHelper.getPowerampPackageName(this)); - intent.putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); + intent.putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); // NOTE: important to send the changed table for an adequate UI / PlayerService reloading intent.putExtra(PowerampAPI.EXTRA_TABLE, TableDefs.PlaylistEntries.TABLE); - if(FORCE_API_ACTIVITY) { + if(MainActivity.FORCE_API_ACTIVITY) { intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); - startActivitySafe(intent); + this.startActivitySafe(intent); } else { - sendBroadcast(intent); + this.sendBroadcast(intent); } } // Make open playlist button active - findViewById(R.id.goto_created_playlist).setEnabled(true); + this.findViewById(R.id.goto_created_playlist).setEnabled(true); } private void gotoCreatedPlaylist() { - if(mLastCreatedPlaylistFilesUri != null) { - startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(mLastCreatedPlaylistFilesUri)); + if(null != mLastCreatedPlaylistFilesUri) { + this.startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(this.mLastCreatedPlaylistFilesUri)); } } private void addToQAndGotoQ() { - ContentResolver cr = getContentResolver(); - Uri queueUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("queue").build(); - ContentValues values = new ContentValues(); + final ContentResolver cr = this.getContentResolver(); + final Uri queueUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("queue").build(); + final ContentValues values = new ContentValues(); // Get max sort from queue int maxSort = 0; - Cursor c = getContentResolver().query(queueUri, new String[]{ "MAX(" + TableDefs.Queue.SORT + ")" }, null, null, null); - if(c != null) { + Cursor c = this.getContentResolver().query(queueUri, new String[]{ "MAX(" + TableDefs.Queue.SORT + ")" }, null, null, null); + if(null != c) { if(c.moveToFirst()) { maxSort = c.getInt(0); } @@ -1302,28 +1295,28 @@ private void addToQAndGotoQ() { // Select up to 10 random files final int numFilesToInsert = 10; - Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build(); - c = getContentResolver().query(filesUri, new String[]{ TableDefs.Files._ID, TableDefs.Files.NAME }, null, null, "RANDOM() LIMIT " + numFilesToInsert); + final Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath("files").build(); + c = this.getContentResolver().query(filesUri, new String[]{ TableDefs.Files._ID, TableDefs.Files.NAME }, null, null, "RANDOM() LIMIT " + numFilesToInsert); int inserted = 0; - if(c != null) { + if(null != c) { int sort = maxSort + 1; // Start from maxSort + 1 while(c.moveToNext()) { - long fileId = c.getLong(0); - String name = c.getString(1); + final long fileId = c.getLong(0); + final String name = c.getString(1); values.clear(); - values.put(getRawColName(TableDefs.Queue.FOLDER_FILE_ID), fileId); - values.put(getRawColName(TableDefs.Queue.SORT), sort); + values.put(MainActivity.getRawColName(TableDefs.Queue.FOLDER_FILE_ID), fileId); + values.put(MainActivity.getRawColName(TableDefs.Queue.SORT), sort); - Uri entryUri = cr.insert(queueUri, values); - if(entryUri != null) { - Log.w(TAG, "addToQAndGotoQ inserted entry fileId=" + fileId + " sort=" + sort + " name=" + name + " entryUri=" + entryUri); + final Uri entryUri = cr.insert(queueUri, values); + if(null != entryUri) { + Log.w(MainActivity.TAG, "addToQAndGotoQ inserted entry fileId=" + fileId + " sort=" + sort + " name=" + name + " entryUri=" + entryUri); sort++; inserted++; } else { - Log.e(TAG, "addToQAndGotoQ FAILED to insert entry fileId=" + fileId); + Log.e(MainActivity.TAG, "addToQAndGotoQ FAILED to insert entry fileId=" + fileId); } } @@ -1332,102 +1325,102 @@ private void addToQAndGotoQ() { Toast.makeText(this, "Inserted files=" + sort, Toast.LENGTH_SHORT).show(); } - if(inserted > 0) { + if(0 < inserted) { // Force Poweramp to reload data in UI / PlayerService as we changed something - Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); + final Intent intent = new Intent(PowerampAPI.ACTION_RELOAD_DATA); intent.setPackage(PowerampAPIHelper.getPowerampPackageName(this)); - intent.putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); + intent.putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); // NOTE: important to send changed table for the adequate UI / PlayerService reloading. This can also make Poweramp to go to Queue intent.putExtra(PowerampAPI.EXTRA_TABLE, TableDefs.Queue.TABLE); - if(FORCE_API_ACTIVITY) { + if(MainActivity.FORCE_API_ACTIVITY) { intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); - startActivitySafe(intent); + this.startActivitySafe(intent); } else { - sendBroadcast(intent); + this.sendBroadcast(intent); } - startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(queueUri)); + this.startActivitySafe(new Intent(PowerampAPI.ACTION_OPEN_LIBRARY).setData(queueUri)); } } private void getComponentNames() { - if(LOG_VERBOSE) Log.w(TAG, "getComponentNames"); - TextView tv = findViewById(R.id.component_names); - SpannableStringBuilder sb = new SpannableStringBuilder(); - appendWithSpan(sb, "Component Names\n", new StyleSpan(Typeface.BOLD)); - appendWithSpan(sb, "Package: ", new StyleSpan(Typeface.BOLD)) - .append(orEmpty(PowerampAPIHelper.getPowerampPackageName(this))) + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "getComponentNames"); + final TextView tv = this.findViewById(R.id.component_names); + final SpannableStringBuilder sb = new SpannableStringBuilder(); + MainActivity.appendWithSpan(sb, "Component Names\n", new StyleSpan(Typeface.BOLD)); + MainActivity.appendWithSpan(sb, "Package: ", new StyleSpan(Typeface.BOLD)) + .append(this.orEmpty(PowerampAPIHelper.getPowerampPackageName(this))) .append("\n"); - appendWithSpan(sb, "PlayerService: ", new StyleSpan(Typeface.BOLD)) - .append(toStringOrEmpty(PowerampAPIHelper.getPlayerServiceComponentName(this))) + MainActivity.appendWithSpan(sb, "PlayerService: ", new StyleSpan(Typeface.BOLD)) + .append(this.toStringOrEmpty(PowerampAPIHelper.getPlayerServiceComponentName(this))) .append("\n"); - appendWithSpan(sb, "MediaBrowserService: ", new StyleSpan(Typeface.BOLD)) - .append(toStringOrEmpty(PowerampAPIHelper.getBrowserServiceComponentName(this))) + MainActivity.appendWithSpan(sb, "MediaBrowserService: ", new StyleSpan(Typeface.BOLD)) + .append(this.toStringOrEmpty(PowerampAPIHelper.getBrowserServiceComponentName(this))) .append("\n"); - appendWithSpan(sb, "API Receiver: ", new StyleSpan(Typeface.BOLD)) - .append(toStringOrEmpty(PowerampAPIHelper.getApiReceiverComponentName(this))) + MainActivity.appendWithSpan(sb, "API Receiver: ", new StyleSpan(Typeface.BOLD)) + .append(this.toStringOrEmpty(PowerampAPIHelper.getApiReceiverComponentName(this))) .append("\n"); - appendWithSpan(sb, "Scanner: ", new StyleSpan(Typeface.BOLD)) - .append(toStringOrEmpty(PowerampAPIHelper.getScannerServiceComponentName(this))) + MainActivity.appendWithSpan(sb, "Scanner: ", new StyleSpan(Typeface.BOLD)) + .append(this.toStringOrEmpty(PowerampAPIHelper.getScannerServiceComponentName(this))) .append("\n"); - appendWithSpan(sb, "Milk Scanner: ", new StyleSpan(Typeface.BOLD)) - .append(toStringOrEmpty(PowerampAPIHelper.getMilkScannerServiceComponentName(this))) + MainActivity.appendWithSpan(sb, "Milk Scanner: ", new StyleSpan(Typeface.BOLD)) + .append(this.toStringOrEmpty(PowerampAPIHelper.getMilkScannerServiceComponentName(this))) .append("\n"); tv.setText(sb); - if(LOG_VERBOSE) Log.w(TAG, "getComponentNames DONE"); + if(MainActivity.LOG_VERBOSE) Log.w(MainActivity.TAG, "getComponentNames DONE"); } - private @NonNull String orEmpty(@Nullable String s) { - if(s == null) return ""; + private @NonNull String orEmpty(@Nullable final String s) { + if(null == s) return ""; return s; } - private @NonNull String toStringOrEmpty(@Nullable ComponentName name) { - return name != null ? name.toString() : ""; + private @NonNull String toStringOrEmpty(@Nullable final ComponentName name) { + return null != name ? name.toString() : ""; } - public static @NonNull String getRawColName(@NonNull String col) { - int dot = col.indexOf('.'); - if(dot >= 0 && dot + 1 <= col.length()) { + public static @NonNull String getRawColName(@NonNull final String col) { + final int dot = col.indexOf('.'); + if(0 <= dot && dot + 1 <= col.length()) { return col.substring(dot + 1); } return col; } - public static void formatTimeS(@NonNull StringBuilder sb, int secs, boolean showPlaceholderForZero) { - if(secs < 0 || secs == 0 && showPlaceholderForZero) { - sb.append(NO_TIME); + public static void formatTimeS(@NonNull final StringBuilder sb, final int secs, final boolean showPlaceholderForZero) { + if(0 > secs || 0 == secs && showPlaceholderForZero) { + sb.append(MainActivity.NO_TIME); return; } - int seconds = secs % 60; + final int seconds = secs % 60; - if(secs < 3600) { // min:sec - int minutes = secs / 60; + if(3600 > secs) { // min:sec + final int minutes = secs / 60; sb.append(minutes).append(':'); } else { // hour:min:sec - int hours = secs / 3600; - int minutes = (secs / 60) % 60; + final int hours = secs / 3600; + final int minutes = (secs / 60) % 60; sb.append(hours).append(':'); - if(minutes < 10) { + if(10 > minutes) { sb.append('0'); } sb.append(minutes).append(':'); } - if(seconds < 10) { + if(10 > seconds) { sb.append('0'); } sb.append(seconds); } - public static void debugDumpIntent(@NonNull String tag, @NonNull String description, @Nullable Intent intent) { - if(intent != null) { - Log.w(tag, description + " debugDumpIntent action=" + intent.getAction() + " extras=" + dumpBundle(intent.getExtras())); - Bundle track = intent.getBundleExtra(PowerampAPI.EXTRA_TRACK); - if(track != null) { - Log.w(tag, "track=" + dumpBundle(track)); + public static void debugDumpIntent(@NonNull final String tag, @NonNull final String description, @Nullable final Intent intent) { + if(null != intent) { + Log.w(tag, description + " debugDumpIntent action=" + intent.getAction() + " extras=" + MainActivity.dumpBundle(intent.getExtras())); + final Bundle track = intent.getBundleExtra(PowerampAPI.EXTRA_TRACK); + if(null != track) { + Log.w(tag, "track=" + MainActivity.dumpBundle(track)); } } else { Log.e(tag, description + " debugDumpIntent intent is null"); @@ -1435,18 +1428,18 @@ public static void debugDumpIntent(@NonNull String tag, @NonNull String descript } @SuppressWarnings("null") - public static @NonNull String dumpBundle(@Nullable Bundle bundle) { - if(bundle == null) { + public static @NonNull String dumpBundle(@Nullable final Bundle bundle) { + if(null == bundle) { return "null bundle"; } - StringBuilder sb = new StringBuilder(); - Set keys = bundle.keySet(); + final StringBuilder sb = new StringBuilder(); + final Set keys = bundle.keySet(); sb.append("\n"); - for(String key : keys) { + for(final String key : keys) { sb.append('\t').append(key).append("="); - Object val = bundle.get(key); + final Object val = bundle.get(key); sb.append(val); - if(val != null) { + if(null != val) { sb.append(" ").append(val.getClass().getSimpleName()); } sb.append("\n"); @@ -1454,9 +1447,9 @@ public static void debugDumpIntent(@NonNull String tag, @NonNull String descript return sb.toString(); } - private static @NonNull SpannableStringBuilder appendWithSpan(@NonNull SpannableStringBuilder sb, @Nullable CharSequence str, @NonNull Object span) { - int start = sb.length(); - sb.append(str != null ? str : ""); + private static @NonNull SpannableStringBuilder appendWithSpan(@NonNull final SpannableStringBuilder sb, @Nullable final CharSequence str, @NonNull final Object span) { + final int start = sb.length(); + sb.append(null != str ? str : ""); sb.setSpan(span, start, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return sb; } diff --git a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/TrackListActivity.java b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/TrackListActivity.java index d9477148..0231e05c 100644 --- a/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/TrackListActivity.java +++ b/poweramp_api_example/src/main/java/com/maxmpz/poweramp/apiexample/TrackListActivity.java @@ -28,7 +28,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import android.util.Log; import android.view.View; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.SimpleCursorAdapter; @@ -37,19 +36,19 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import com.maxmpz.poweramp.player.TableDefs; @SuppressWarnings("deprecation") -public class TrackListActivity extends ListActivity implements OnItemClickListener { +public class TrackListActivity extends ListActivity implements AdapterView.OnItemClickListener { private static final String TAG = "TrackListActivity"; private Uri mUri; @Override - protected void onCreate(Bundle savedInstanceState){ + protected void onCreate(final Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_tracklist); - mUri = getIntent().getData(); + this.mUri = this.getIntent().getData(); - Cursor c = this.getContentResolver().query(mUri, + final Cursor c = getContentResolver().query(this.mUri, new String[]{ "folder_files._id AS _id", TableDefs.Files.TITLE_TAG + " AS title_tag", // NOTE: AS ... is needed for SimpleCursorAdapter, we probably don't need for our real custom adapters TableDefs.Artists.ARTIST + " AS artist" @@ -57,27 +56,27 @@ protected void onCreate(Bundle savedInstanceState){ null, null, null); // NOTE: using null as order argument - this results in user selected sorting - the same way as shown in Poweramp list - if(c != null) startManagingCursor(c); + if(null != c) this.startManagingCursor(c); - SimpleCursorAdapter adapter = new SimpleCursorAdapter( + final SimpleCursorAdapter adapter = new SimpleCursorAdapter( this, // Context. android.R.layout.two_line_list_item, c, new String[] { "title_tag", "artist" }, new int[] {android.R.id.text1, android.R.id.text2}, 0); - setListAdapter(adapter); + this.setListAdapter(adapter); - ListView list = (ListView)findViewById(android.R.id.list); + final ListView list = this.findViewById(android.R.id.list); list.setOnItemClickListener(this); } @Override - public void onItemClick(AdapterView arg0, View arg1, int arg2, long id) { - Uri uri = mUri.buildUpon() + public void onItemClick(final AdapterView arg0, final View arg1, final int arg2, final long id) { + final Uri uri = this.mUri.buildUpon() .appendEncodedPath(Long.toString(id)) .build(); - Log.w(TAG, "onItemClick uri=>" + uri); + Log.w(TrackListActivity.TAG, "onItemClick uri=>" + uri); PowerampAPIHelper.sendPAIntent(this, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.OPEN_TO_PLAY) diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPI.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPI.java index fe50f0ce..0218355c 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPI.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPI.java @@ -2,8 +2,9 @@ import com.maxmpz.poweramp.player.PowerampAPI; -public final class PeqAPI { - public static final String ACTION_ASK_FOR_DATA_PERMISSION = PowerampAPI.ACTION_ASK_FOR_DATA_PERMISSION; +public enum PeqAPI { + ; + public static final String ACTION_ASK_FOR_DATA_PERMISSION = PowerampAPI.ACTION_ASK_FOR_DATA_PERMISSION; public static final String ACTION_RELOAD_DATA = PowerampAPI.ACTION_RELOAD_DATA; public static final String ACTION_API_COMMAND = "com.maxmpz.equalizer.API_COMMAND"; @@ -38,14 +39,15 @@ public final class PeqAPI { */ public static final String EXTRA_PRESETS = "presets"; - public static final class Commands { - public static final int STOP_SERVICE = PowerampAPI.Commands.STOP_SERVICE; + public enum Commands { + ; + public static final int STOP_SERVICE = PowerampAPI.Commands.STOP_SERVICE; } /** @see PowerampAPI#CALL_SET_PREFERENCE */ public static final String CALL_SET_PREFERENCE = PowerampAPI.CALL_SET_PREFERENCE; - public final static class MilkScanner extends PowerampAPI.MilkScanner {} + public static final class MilkScanner extends PowerampAPI.MilkScanner {} /** diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPIHelper.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPIHelper.java index 7f6ad6ec..4ff9deaa 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPIHelper.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/equalizer/PeqAPIHelper.java @@ -28,9 +28,12 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import android.content.pm.ResolveInfo; import android.util.Log; +import com.maxmpz.poweramp.player.PowerampAPI; -public class PeqAPIHelper { - private static final String TAG = "PeqAPIHelper"; + +public enum PeqAPIHelper { + ; + private static final String TAG = "PeqAPIHelper"; private static final boolean LOG = false; private static String sPak; @@ -44,12 +47,12 @@ public class PeqAPIHelper { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached package name or null if it's not installed
*/ - public static String getPackageName(Context context) { - String pak = sPak; - if(pak == null) { - ComponentName activityName = getApiActivityComponentName(context); - if(activityName != null) { - pak = sPak = activityName.getPackageName(); + public static String getPackageName(final Context context) { + String pak = PeqAPIHelper.sPak; + if(null == pak) { + final ComponentName activityName = PeqAPIHelper.getApiActivityComponentName(context); + if(null != activityName) { + pak = PeqAPIHelper.sPak = activityName.getPackageName(); } } return pak; @@ -60,16 +63,16 @@ public static String getPackageName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached API activity component name, or null if not installed */ - public static ComponentName getApiActivityComponentName(Context context) { - ComponentName componentName = sApiActivityComponentName; - if(componentName == null) { + public static ComponentName getApiActivityComponentName(final Context context) { + ComponentName componentName = PeqAPIHelper.sApiActivityComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveActivity(new Intent(PeqAPI.ACTION_API_COMMAND), 0); - if(info != null && info.activityInfo != null) { - componentName = sApiActivityComponentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); + final ResolveInfo info = context.getPackageManager().resolveActivity(new Intent(PeqAPI.ACTION_API_COMMAND), 0); + if(null != info && null != info.activityInfo) { + componentName = PeqAPIHelper.sApiActivityComponentName = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PeqAPIHelper.TAG, "", th); } } return componentName; @@ -79,16 +82,16 @@ public static ComponentName getApiActivityComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached milk scanner component name, or null if not installed */ - public static ComponentName getMilkScannerServiceComponentName(Context context) { - ComponentName componentName = sMilkScanServiceComponentName; - if(componentName == null) { + public static ComponentName getMilkScannerServiceComponentName(final Context context) { + ComponentName componentName = PeqAPIHelper.sMilkScanServiceComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent(PeqAPI.MilkScanner.ACTION_SCAN).setPackage(getPackageName(context)), 0); - if(info != null && info.serviceInfo != null) { - componentName = sMilkScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + final ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.MilkScanner.ACTION_SCAN).setPackage(PeqAPIHelper.getPackageName(context)), 0); + if(null != info && null != info.serviceInfo) { + componentName = PeqAPIHelper.sMilkScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PeqAPIHelper.TAG, "", th); } } return componentName; @@ -98,12 +101,12 @@ public static ComponentName getMilkScannerServiceComponentName(Context context) * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached API receiver component name, or null if not installed */ - public static ComponentName getApiReceiverComponentName(Context context) { - ComponentName componentName = sApiReceiverComponentName; - if(componentName == null) { - String pak = getPackageName(context); - if(pak != null) { - componentName = sApiReceiverComponentName = new ComponentName(pak, PeqAPI.API_RECEIVER_NAME); + public static ComponentName getApiReceiverComponentName(final Context context) { + ComponentName componentName = PeqAPIHelper.sApiReceiverComponentName; + if(null == componentName) { + final String pak = PeqAPIHelper.getPackageName(context); + if(null != pak) { + componentName = PeqAPIHelper.sApiReceiverComponentName = new ComponentName(pak, PeqAPI.API_RECEIVER_NAME); } } return componentName; @@ -113,26 +116,26 @@ public static ComponentName getApiReceiverComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached build number
*/ - public static int getPowerampBuild(Context context) { - if(sBuild == 0) { - String pak = getPackageName(context); - if(pak != null) { + public static int getPowerampBuild(final Context context) { + if(0 == sBuild) { + final String pak = PeqAPIHelper.getPackageName(context); + if(null != pak) { try { - PackageInfo pi = context.getPackageManager().getPackageInfo(pak, 0); - sBuild = pi.versionCode > 1000 ? pi.versionCode / 1000 : pi.versionCode; - } catch(Throwable th) { - Log.e(TAG, "", th); + final PackageInfo pi = context.getPackageManager().getPackageInfo(pak, 0); + PeqAPIHelper.sBuild = 1000 < pi.versionCode ? pi.versionCode / 1000 : pi.versionCode; + } catch(final Throwable th) { + Log.e(PeqAPIHelper.TAG, "", th); } } } - return sBuild; + return PeqAPIHelper.sBuild; } /** * THREADING: can be called from any thread
* @return intent to send with sendPAIntent */ - public static Intent newAPIIntent(Context context) { + public static Intent newAPIIntent(final Context context) { return new Intent(PeqAPI.ACTION_API_COMMAND); } @@ -140,24 +143,24 @@ public static Intent newAPIIntent(Context context) { /** * THREADING: can be called from any thread
*/ - public static void sendPAIntent(Context context, Intent intent) { - sendPAIntent(context, intent, false); + public static void sendPAIntent(final Context context, final Intent intent) { + PeqAPIHelper.sendPAIntent(context, intent, false); } /** * THREADING: can be called from any thread * @param sendToActivity if true, we're sending intent to the activity */ - public static void sendPAIntent(Context context, Intent intent, boolean sendToActivity) { + public static void sendPAIntent(final Context context, final Intent intent, final boolean sendToActivity) { intent.putExtra(PeqAPI.EXTRA_PACKAGE, context.getPackageName()); if(sendToActivity) { - intent.setComponent(getApiActivityComponentName(context)); + intent.setComponent(PeqAPIHelper.getApiActivityComponentName(context)); if(!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } else { - intent.setComponent(getApiReceiverComponentName(context)); + intent.setComponent(PeqAPIHelper.getApiReceiverComponentName(context)); context.sendBroadcast(intent); } } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/EqPresetConsts.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/EqPresetConsts.java index 843ccfbd..00aeed04 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/EqPresetConsts.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/EqPresetConsts.java @@ -5,14 +5,14 @@ */ public interface EqPresetConsts { /** Preset type not set */ - public static final int TYPE_UNKNOWN = -1; + int TYPE_UNKNOWN = -1; /** User created or default user preset */ - public static final int TYPE_USER = 0; + int TYPE_USER = 0; /** Built-in preset */ - public static final int TYPE_BUILT_IN = 10; + int TYPE_BUILT_IN = 10; /** AutoEq preset */ - public static final int TYPE_AUTO_EQ = 20; + int TYPE_AUTO_EQ = 20; } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PaSampleFormat.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PaSampleFormat.java index 0c482815..2ade525b 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PaSampleFormat.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PaSampleFormat.java @@ -4,8 +4,9 @@ import org.eclipse.jdt.annotation.NonNull; -public final class PaSampleFormat { - public static final int PA_SAMPLE_FMT_NONE = -1; +public enum PaSampleFormat { + ; + public static final int PA_SAMPLE_FMT_NONE = -1; public static final int PA_SAMPLE_FMT_U8 = 0; ///< unsigned 8 bits public static final int PA_SAMPLE_FMT_S16 = 1; ///< signed 16 bits @@ -28,86 +29,85 @@ public final class PaSampleFormat { public static final int PA_SAMPLE_FMT_NB = 22; - public static boolean isValidFormat(int format, boolean allowReserve) { - if(format < 0) return false; - if(format >= PA_SAMPLE_FMT_NB) return false; - if(!allowReserve && format > PA_SAMPLE_FMT_S64P && format < PA_SAMPLE_FMT_S24) return false; - return true; - } + public static boolean isValidFormat(final int format, final boolean allowReserve) { + if(0 > format) return false; + if(PA_SAMPLE_FMT_NB <= format) return false; + return allowReserve || PA_SAMPLE_FMT_S64P >= format || PA_SAMPLE_FMT_S24 <= format; + } /** This is storage bits per given sample */ - public static int getBitsPerSample(int sampleFormat) { + public static int getBitsPerSample(final int sampleFormat) { switch(sampleFormat) { default: - case PA_SAMPLE_FMT_NONE: + case PaSampleFormat.PA_SAMPLE_FMT_NONE: return 0; - case PA_SAMPLE_FMT_U8: + case PaSampleFormat.PA_SAMPLE_FMT_U8: return 8; - case PA_SAMPLE_FMT_S16: + case PaSampleFormat.PA_SAMPLE_FMT_S16: return 16; - case PA_SAMPLE_FMT_S32: + case PaSampleFormat.PA_SAMPLE_FMT_S32: return 32; - case PA_SAMPLE_FMT_FLT: + case PaSampleFormat.PA_SAMPLE_FMT_FLT: return 32; - case PA_SAMPLE_FMT_DBL: + case PaSampleFormat.PA_SAMPLE_FMT_DBL: return 64; - case PA_SAMPLE_FMT_U8P: + case PaSampleFormat.PA_SAMPLE_FMT_U8P: return 8; - case PA_SAMPLE_FMT_S16P: + case PaSampleFormat.PA_SAMPLE_FMT_S16P: return 16; - case PA_SAMPLE_FMT_S32P: + case PaSampleFormat.PA_SAMPLE_FMT_S32P: return 32; - case PA_SAMPLE_FMT_FLTP: + case PaSampleFormat.PA_SAMPLE_FMT_FLTP: return 32; - case PA_SAMPLE_FMT_DBLP: + case PaSampleFormat.PA_SAMPLE_FMT_DBLP: return 64; - case PA_SAMPLE_FMT_S24: + case PaSampleFormat.PA_SAMPLE_FMT_S24: return 24; - case PA_SAMPLE_FMT_S8_24: + case PaSampleFormat.PA_SAMPLE_FMT_S8_24: return 32; - case PA_SAMPLE_FMT_S64: - case PA_SAMPLE_FMT_S64P: + case PaSampleFormat.PA_SAMPLE_FMT_S64: + case PaSampleFormat.PA_SAMPLE_FMT_S64P: return 64; } } /** This is storage bits per given sample */ - public static int getBytesPerSample(int sampleFormat) { - return getBitsPerSample(sampleFormat) / 8; + public static int getBytesPerSample(final int sampleFormat) { + return PaSampleFormat.getBitsPerSample(sampleFormat) / 8; } /** This is significant range bits per given sample, i.e. 24 for Float32 or S8_24 */ - public static int getSignificantBitsPerSample(int sampleFormat) { + public static int getSignificantBitsPerSample(final int sampleFormat) { switch(sampleFormat) { default: - case PA_SAMPLE_FMT_NONE: + case PaSampleFormat.PA_SAMPLE_FMT_NONE: return 0; - case PA_SAMPLE_FMT_U8: + case PaSampleFormat.PA_SAMPLE_FMT_U8: return 8; - case PA_SAMPLE_FMT_S16: + case PaSampleFormat.PA_SAMPLE_FMT_S16: return 16; - case PA_SAMPLE_FMT_S32: + case PaSampleFormat.PA_SAMPLE_FMT_S32: return 32; - case PA_SAMPLE_FMT_FLT: + case PaSampleFormat.PA_SAMPLE_FMT_FLT: return 24; - case PA_SAMPLE_FMT_FLTP: + case PaSampleFormat.PA_SAMPLE_FMT_FLTP: return 24; - case PA_SAMPLE_FMT_DBL: + case PaSampleFormat.PA_SAMPLE_FMT_DBL: return 53; - case PA_SAMPLE_FMT_U8P: + case PaSampleFormat.PA_SAMPLE_FMT_U8P: return 8; - case PA_SAMPLE_FMT_S16P: + case PaSampleFormat.PA_SAMPLE_FMT_S16P: return 16; - case PA_SAMPLE_FMT_S32P: + case PaSampleFormat.PA_SAMPLE_FMT_S32P: return 32; - case PA_SAMPLE_FMT_DBLP: + case PaSampleFormat.PA_SAMPLE_FMT_DBLP: return 53; - case PA_SAMPLE_FMT_S24: + case PaSampleFormat.PA_SAMPLE_FMT_S24: return 24; - case PA_SAMPLE_FMT_S8_24: // This is Q8.23 + case PaSampleFormat.PA_SAMPLE_FMT_S8_24: // This is Q8.23 return 24; // NOTE: not sure about this, actually this is closer to normal float, thus this is 24 bit - case PA_SAMPLE_FMT_S64: - case PA_SAMPLE_FMT_S64P: + case PaSampleFormat.PA_SAMPLE_FMT_S64: + case PaSampleFormat.PA_SAMPLE_FMT_S64P: return 53; } } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PipelineConsts.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PipelineConsts.java index 9306a393..93ffb436 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PipelineConsts.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PipelineConsts.java @@ -23,104 +23,104 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface PipelineConsts { /** The format used internally in DSP kernels */ - public static final int DSP_FORMAT = PaSampleFormat.PA_SAMPLE_FMT_DBL; + int DSP_FORMAT = PaSampleFormat.PA_SAMPLE_FMT_DBL; /** The format used between pipeline plugins */ - public static final int PIPELINE_FORMAT = PaSampleFormat.PA_SAMPLE_FMT_FLT; + int PIPELINE_FORMAT = PaSampleFormat.PA_SAMPLE_FMT_FLT; // For getPipelineParamInt() - public static final int SUBSYSTEM_PIPELINE = 0; - public static final int SUBSYSTEM_DSP_TH = 1; - public static final int SUBSYSTEM_DECODER_TH = 2; - public static final int SUBSYSTEM_OUTPUT = 3; // probably change to pipeline? + int SUBSYSTEM_PIPELINE = 0; + int SUBSYSTEM_DSP_TH = 1; + int SUBSYSTEM_DECODER_TH = 2; + int SUBSYSTEM_OUTPUT = 3; // probably change to pipeline? // For queueMsg() - public static final int PLUGIN_ID_SUBSYSTEM_PIPELINE = 0; - public static final int PLUGIN_ID_SUBSYSTEM_DECODER_TH = 1; // NOTE: sync with NativePluginManager.PLUGIN_ID_SUBSYSTEM_LAST - public static final int PLUGIN_ID_SUBSYSTEM_DSP_TH = 2; + int PLUGIN_ID_SUBSYSTEM_PIPELINE = 0; + int PLUGIN_ID_SUBSYSTEM_DECODER_TH = 1; // NOTE: sync with NativePluginManager.PLUGIN_ID_SUBSYSTEM_LAST + int PLUGIN_ID_SUBSYSTEM_DSP_TH = 2; /* * NOTE: raw native plugin value, not resolved vs Android audio subsystem */ - public static final int PA_OUTPUT_PARAM_SAMPLE_RATE = 1; + int PA_OUTPUT_PARAM_SAMPLE_RATE = 1; /* * NOTE: raw native plugin value, not resolved vs Android audio subsystem */ - public static final int PA_OUTPUT_PARAM_SAMPLE_BITS = 2; - public static final int PA_OUTPUT_PARAM_ANDROID_SESSION_ID = 3; - public static final int PA_OUTPUT_PARAM_RESTART_LATENCY_MS = 4; - public static final int PA_OUTPUT_PARAM_ANDROID_AUDIO_STREAM = 5; + int PA_OUTPUT_PARAM_SAMPLE_BITS = 2; + int PA_OUTPUT_PARAM_ANDROID_SESSION_ID = 3; + int PA_OUTPUT_PARAM_RESTART_LATENCY_MS = 4; + int PA_OUTPUT_PARAM_ANDROID_AUDIO_STREAM = 5; /** NOTE: not used, use DSP_TH_OUTPUT_FORMAT */ - public static final int PA_OUTPUT_PARAM_SAMPLE_FORMAT = 6; - public static final int PA_OUTPUT_PARAM_DEFAULT_MASTER_VOLUME_LEVELS = 20; + int PA_OUTPUT_PARAM_SAMPLE_FORMAT = 6; + int PA_OUTPUT_PARAM_DEFAULT_MASTER_VOLUME_LEVELS = 20; - public static final int PA_OUTPUT_PARAM_FIRST_CUSTOM = 0x1000; + int PA_OUTPUT_PARAM_FIRST_CUSTOM = 0x1000; // Internal - public static final int PA_OUTPUT_PARAM_AUDIO_IO_HANDLE = 0x80000001; + int PA_OUTPUT_PARAM_AUDIO_IO_HANDLE = 0x80000001; // getPipelineParamInt() SUBSYSTEM_PIPELINE - public static final int PARAM_LAST_DECODER_IX = 1; // Never used ATM - public static final int PARAM_LAST_DECODER_ID = 2; + int PARAM_LAST_DECODER_IX = 1; // Never used ATM + int PARAM_LAST_DECODER_ID = 2; // getPipelineParamInt() SUBSYSTEM_DSP_TH // NOTE: sync with dsp_threads.h - public static final int DSP_TH_OUTPUT_ID = 1; - public static final int DSP_TH_PIPELINE_LATENCY = 2; - public static final int DSP_TH_OUTPUT_LATENCY = 3; - public static final int DSP_TH_OUTPUT_CAPS = 4; + int DSP_TH_OUTPUT_ID = 1; + int DSP_TH_PIPELINE_LATENCY = 2; + int DSP_TH_OUTPUT_LATENCY = 3; + int DSP_TH_OUTPUT_CAPS = 4; /** * This is active DSP and output sample rate, always corresponds to the negotiated sample rate, but not the device sample rate.
* NOTE: we ALWAYS run DSP and output on the same sample rate (though format still can differ, as we always use float32 for DSP) * */ - public static final int DSP_TH_AND_OUTPUT_SAMPLE_RATE = 5; + int DSP_TH_AND_OUTPUT_SAMPLE_RATE = 5; /** This is active output format, always corresponds to the negotiated format, but it is not the end device format */ - public static final int DSP_TH_OUTPUT_FORMAT = 6; - public static final int DSP_TH_BUFFERS = 7; - public static final int DSP_TH_BUFFER_FRAMES = 8; + int DSP_TH_OUTPUT_FORMAT = 6; + int DSP_TH_BUFFERS = 7; + int DSP_TH_BUFFER_FRAMES = 8; // NOTE: sync with plugininterface-output.h - public static final int PA_OUTPUT_CAP_ALWAYS_UNITY_GAIN = 0x0010; - public static final int PA_OUTPUT_CAP_NO_HEADROOM_GAIN = 0x0020; - public static final int PA_OUTPUT_CAP_NO_EQU = 0x0040; - public static final int PA_OUTPUT_CAP_FLT_EXTENDED_DYN_RANGE = 0x0080; - public static final int PA_OUTPUT_CAP_PAUSE_FAST_VOLUME = 0x0100; - public static final int PA_OUTPUT_CAP_SEEK_FAST_VOLUME = 0x0200; - public static final int PA_OUTPUT_CAP_TRACK_CHANGE_FAST_VOLUME = 0x0400; - public static final int PA_OUTPUT_CAP_NEEDS_VOLUME_PROVIDER = 0x0800; - public static final int PA_OUTPUT_CAP_CUSTOM_MASTER_VOLUME = 0x1000; - public static final int PA_OUTPUT_CAP_NO_DUCK = 0x2000; - public static final int PA_OUTPUT_CAP_TRACK_PLAYBACK = 0x4000; - public static final int PA_OUTPUT_CAP_NEEDS_VOL_UI = 0x8000; - public static final int PA_OUTPUT_CAP_RAW = 0x0008; - public static final int PA_OUTPUT_CAP_NO_MUSIC_STREAM_VOL = 0x0004; - public static final int PA_OUTPUT_CAP_PTS_UI = 0x0002; - public static final int PA_OUTPUT_CAP_NO_AUDIO_FOCUS = 0x100000; - public static final int PA_OUTPUT_CAP_USE_STREAM3 = 0x200000; - public static final int PA_OUTPUT_CAP_DELAYED_FORMAT = 0x400000; + int PA_OUTPUT_CAP_ALWAYS_UNITY_GAIN = 0x0010; + int PA_OUTPUT_CAP_NO_HEADROOM_GAIN = 0x0020; + int PA_OUTPUT_CAP_NO_EQU = 0x0040; + int PA_OUTPUT_CAP_FLT_EXTENDED_DYN_RANGE = 0x0080; + int PA_OUTPUT_CAP_PAUSE_FAST_VOLUME = 0x0100; + int PA_OUTPUT_CAP_SEEK_FAST_VOLUME = 0x0200; + int PA_OUTPUT_CAP_TRACK_CHANGE_FAST_VOLUME = 0x0400; + int PA_OUTPUT_CAP_NEEDS_VOLUME_PROVIDER = 0x0800; + int PA_OUTPUT_CAP_CUSTOM_MASTER_VOLUME = 0x1000; + int PA_OUTPUT_CAP_NO_DUCK = 0x2000; + int PA_OUTPUT_CAP_TRACK_PLAYBACK = 0x4000; + int PA_OUTPUT_CAP_NEEDS_VOL_UI = 0x8000; + int PA_OUTPUT_CAP_RAW = 0x0008; + int PA_OUTPUT_CAP_NO_MUSIC_STREAM_VOL = 0x0004; + int PA_OUTPUT_CAP_PTS_UI = 0x0002; + int PA_OUTPUT_CAP_NO_AUDIO_FOCUS = 0x100000; + int PA_OUTPUT_CAP_USE_STREAM3 = 0x200000; + int PA_OUTPUT_CAP_DELAYED_FORMAT = 0x400000; // 18 // NOTE: plugininterface-internal.h // NOTE: used for get_options() only - public static final int PA_OUTPUT_CAP_FORCED_UNITY_GAIN = 0x20000; - public static final int PA_OUTPUT_CAP_OEM_VARIANT = 0x40000; // Used for caps as well + int PA_OUTPUT_CAP_FORCED_UNITY_GAIN = 0x20000; + int PA_OUTPUT_CAP_OEM_VARIANT = 0x40000; // Used for caps as well // 2 - public static final int UI_FLAG_NO_DVC_DUE_TO_BT_ABSVOL = 0x0001; + int UI_FLAG_NO_DVC_DUE_TO_BT_ABSVOL = 0x0001; /** Volume update broadcast */ - public static int PA_BROADCAST_VOLUME = 1; + int PA_BROADCAST_VOLUME = 1; - public static final int MSG_SET_NO_DVC_HEADROOM_MB = 0x0009; // NOTE: immediately applies this. NOTE: public - can be used by java code + int MSG_SET_NO_DVC_HEADROOM_MB = 0x0009; // NOTE: immediately applies this. NOTE: public - can be used by java code - public static final int FADE_NO_FADE = 0; - public static final int FADE_IN_OUT = 1; - public static final int FADE_CROSSFADE = 2; + int FADE_NO_FADE = 0; + int FADE_IN_OUT = 1; + int FADE_CROSSFADE = 2; - public static final int CROSSFADE_NO_FADE = 0; - public static final int CROSSFADE_NO_GAPLESS = 1; - public static final int CROSSFADE_ALL = 2; - public static final int CROSSFADE_SHUFFLE = 3; - public static final int CROSSFADE_MAX = 3; + int CROSSFADE_NO_FADE = 0; + int CROSSFADE_NO_GAPLESS = 1; + int CROSSFADE_ALL = 2; + int CROSSFADE_SHUFFLE = 3; + int CROSSFADE_MAX = 3; } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPI.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPI.java index 3eb63521..302c9c99 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPI.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPI.java @@ -93,8 +93,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * */ @SuppressWarnings({"WeakerAccess", "Unused"}) -public final class PowerampAPI { - /** +public enum PowerampAPI { + ; + /** * Defines PowerampAPI version */ public static final int VERSION = 855; @@ -122,7 +123,7 @@ public final class PowerampAPI { /** * Root data provider uri */ - public static final Uri ROOT_URI = new Uri.Builder().scheme("content").authority(AUTHORITY).build(); + public static final Uri ROOT_URI = new Uri.Builder().scheme("content").authority(PowerampAPI.AUTHORITY).build(); /** * Authority used for album art provider @@ -131,7 +132,7 @@ public final class PowerampAPI { /** * Root album art provider uri */ - public static final Uri AA_ROOT_URI = new Uri.Builder().scheme("content").authority(AA_AUTHORITY).build(); + public static final Uri AA_ROOT_URI = new Uri.Builder().scheme("content").authority(PowerampAPI.AA_AUTHORITY).build(); /** * AA_AUTHORITY accepted parameter - get HD image. Default is true. @@ -221,8 +222,9 @@ public final class PowerampAPI { * Command values for {@link #EXTRA_COMMAND} extra.
* Alternatively, Commands field name can be used instead of integer value, e.g. "PAUSE", instead of 2 */ - public static final class Commands { - /** + public enum Commands { + ; + /** * Extras:
* {@code boolean keepService} - (optional) if true, Poweramp won't unload player service. Notification will be appropriately updated
* {@code boolean beep} - (optional) if true, Poweramp will beep on playback command @@ -596,65 +598,65 @@ public static final class Commands { public static final int SET_VIS_PRESET = 200; - public static @NonNull String cmdToString(int cmd) { + public static @NonNull String cmdToString(final int cmd) { switch(cmd) { - case TOGGLE_PLAY_PAUSE: + case Commands.TOGGLE_PLAY_PAUSE: return "TOGGLE_PLAY_PAUSE"; - case PAUSE: + case Commands.PAUSE: return "PAUSE"; - case RESUME: + case Commands.RESUME: return "RESUME"; - case NEXT: + case Commands.NEXT: return "NEXT"; - case PREVIOUS: + case Commands.PREVIOUS: return "PREVIOUS"; - case NEXT_IN_CAT: + case Commands.NEXT_IN_CAT: return "NEXT_IN_CAT"; - case PREVIOUS_IN_CAT: + case Commands.PREVIOUS_IN_CAT: return "PREVIOUS_IN_CAT"; - case REPEAT: + case Commands.REPEAT: return "REPEAT"; - case SHUFFLE: + case Commands.SHUFFLE: return "SHUFFLE"; - case BEGIN_FAST_FORWARD: + case Commands.BEGIN_FAST_FORWARD: return "BEGIN_FAST_FORWARD"; - case END_FAST_FORWARD: + case Commands.END_FAST_FORWARD: return "END_FAST_FORWARD"; - case BEGIN_REWIND: + case Commands.BEGIN_REWIND: return "BEGIN_REWIND"; - case END_REWIND: + case Commands.END_REWIND: return "END_REWIND"; - case STOP: + case Commands.STOP: return "STOP"; - case SEEK: + case Commands.SEEK: return "SEEK"; - case POS_SYNC: + case Commands.POS_SYNC: return "POS_SYNC"; - case OPEN_TO_PLAY: + case Commands.OPEN_TO_PLAY: return "OPEN_TO_PLAY"; - case SET_EQU_PRESET: + case Commands.SET_EQU_PRESET: return "SET_EQU_PRESET"; - case SET_EQU_STRING: + case Commands.SET_EQU_STRING: return "SET_EQU_STRING"; - case SET_EQU_BAND: + case Commands.SET_EQU_BAND: return "SET_EQU_BAND"; - case SET_EQU_ENABLED: + case Commands.SET_EQU_ENABLED: return "SET_EQU_ENABLED"; - case STOP_SERVICE: + case Commands.STOP_SERVICE: return "STOP_SERVICE"; - case SLEEP_TIMER: + case Commands.SLEEP_TIMER: return "SLEEP_TIMER"; - case SET_VIS_PRESET: + case Commands.SET_VIS_PRESET: return "SET_VIS_PRESET"; - case LIKE: + case Commands.LIKE: return "LIKE"; - case UNLIKE: + case Commands.UNLIKE: return "UNLIKE"; - case TOGGLE_RATING: + case Commands.TOGGLE_RATING: return "TOGGLE_RATING"; - case SEEK_JUMP_FORWARD: + case Commands.SEEK_JUMP_FORWARD: return "SEEK_JUMP_FORWARD"; - case SEEK_JUMP_BACKWARD: + case Commands.SEEK_JUMP_BACKWARD: return "SEEK_JUMP_BACKWARD"; default: @@ -929,7 +931,7 @@ public static final class Commands { * {@code String name} - preset name. If no name extra exists, it's not a preset
* {@code long id} - preset id. If no id extra exists, it's not a preset
* {@code String value} - equalizer and tone values in format:
- *
bass=pos_float|treble=pos_float|31=float|62=float|....|16K=float|preamp=0.0 ... 2.0
+ *
{@code bass=pos_float|treble=pos_float|31=float|62=float|....|16K=float|preamp=0.0 ... 2.0}
* where float = -1.0 ... 1.0, pos_float = 0.0 ... 1.0
* {@code boolean equ} - true if equalizer bands are enabled
* {@code boolean tone} - true if tone bands are enabled
@@ -1234,8 +1236,9 @@ public static final class Commands { /** * Shuffle extras values */ - public static final class ShuffleMode { - /** + public enum ShuffleMode { + ; + /** * No any shuffle selected */ public static final int SHUFFLE_NONE = 0; @@ -1265,20 +1268,21 @@ public static final class ShuffleMode { */ public static final int SHUFFLE_SONGS_HIER = 5; - public static boolean areSongsShuffled(int shuffle) { - return shuffle == SHUFFLE_ALL || shuffle == SHUFFLE_SONGS || shuffle == SHUFFLE_SONGS_AND_CATS; + public static boolean areSongsShuffled(final int shuffle) { + return SHUFFLE_ALL == shuffle || SHUFFLE_SONGS == shuffle || SHUFFLE_SONGS_AND_CATS == shuffle; } - public static boolean areCatsShuffled(int shuffle) { - return shuffle == SHUFFLE_CATS || shuffle == SHUFFLE_SONGS_AND_CATS; + public static boolean areCatsShuffled(final int shuffle) { + return SHUFFLE_CATS == shuffle || SHUFFLE_SONGS_AND_CATS == shuffle; } } /** * Repeat extras values */ - public static final class RepeatMode { - /** + public enum RepeatMode { + ; + /** * Repeat is disabled */ public static final int REPEAT_NONE = 0; @@ -1312,8 +1316,9 @@ public static final class RepeatMode { /** * Vis extras values */ - public static final class VisMode { - /** + public enum VisMode { + ; + /** * Visualization is disabled */ public static final int VIS_NONE = 0; @@ -1336,8 +1341,9 @@ public static final class VisMode { * Since build 948 all these fields are also exposed to {@link #ACTION_TRACK_CHANGED} and {@link #ACTION_TRACK_CHANGED_EXPLICIT} * extras directly. */ - public static final class Track { - /** + public enum Track { + ; + /** * Max number to use for filename numbers, e.g. 1-track.mp3 is considered a track #1, but 100-track.mp3 is not */ public static final int MAX_FILE_NUMBER = 99; @@ -1509,8 +1515,9 @@ public static final class Track { /** * {@link PowerampAPI.Track} {@link #FILE_TYPE} values */ - public static class FileType { - public static final int TYPE_UNKNOWN = -1; + public enum FileType { + ; + public static final int TYPE_UNKNOWN = -1; public static final int TYPE_MP3 = 0; public static final int TYPE_FLAC = 1; public static final int TYPE_M4A = 2; @@ -1545,46 +1552,47 @@ public static class FileType { */ public interface Flags { /** Track wasn't advanced */ - public static final int FLAG_ADVANCE_NONE = 0; + int FLAG_ADVANCE_NONE = 0; /** Track was advanced forward */ - public static final int FLAG_ADVANCE_FORWARD = 0x1; + int FLAG_ADVANCE_FORWARD = 0x1; /** Track was advanced backward */ - public static final int FLAG_ADVANCE_BACKWARD = 0x2; + int FLAG_ADVANCE_BACKWARD = 0x2; /** Track category was advanced forward */ - public static final int FLAG_ADVANCE_FORWARD_CAT = 0x3; + int FLAG_ADVANCE_FORWARD_CAT = 0x3; /** Track category was advanced backward */ - public static final int FLAG_ADVANCE_BACKWARD_CAT = 0x4; + int FLAG_ADVANCE_BACKWARD_CAT = 0x4; /** * Track is manually selected by user from the list */ - public static final int FLAG_ADVANCE_BY_USER = 0x5; + int FLAG_ADVANCE_BY_USER = 0x5; /** Mask for FLAG_ADVANCE_* values */ - public static final int FLAG_ADVANCE_MASK = 0x7; + int FLAG_ADVANCE_MASK = 0x7; /** * Track was advanced from the notification.
* If set, event comes from the notification ui and we will animate aa update then */ - public static final int FLAG_NOTIFICATION_UI = 0x20; + int FLAG_NOTIFICATION_UI = 0x20; /** Indicates the track is the first in Poweramp service session */ - public static final int FLAG_FIRST_IN_PLAYER_SESSION = 0x40; + int FLAG_FIRST_IN_PLAYER_SESSION = 0x40; /** * The track failed to load for any reason * @since 948 */ - public static final int FLAG_FAILED = 0x80; + int FLAG_FAILED = 0x80; } - public static final class TagStatus { - public static final int TAG_NOT_SCANNED = 0; + public enum TagStatus { + ; + public static final int TAG_NOT_SCANNED = 0; public static final int TAG_SCANNED = 1; /** Currently used only for LRC files */ @@ -1595,8 +1603,9 @@ public static final class TagStatus { * Values for {@link #LYRICS_STATE} * @since 948 */ - public static final class LyricsState { - /** + public enum LyricsState { + ; + /** * No lyrics detected or cached for the track * @since 948 */ @@ -1621,8 +1630,9 @@ public static final class LyricsState { /** * {@link PowerampAPI.Track} {@link PowerampAPI.Track#CAT} categories */ - public static final class Cats { - /** Root library category. Not used in Poweramp v3. */ + public enum Cats { + ; + /** Root library category. Not used in Poweramp v3. */ @Deprecated public static final int ROOT = 0; @@ -1667,16 +1677,16 @@ public static final class Cats { public static final int RECENTLY_ADDED = 53; public static final int LONG = 55; - private Cats() {} - } + } /** * Describes Poweramp scanner related actions.
* Use {@link PowerampAPIHelper#getScannerServiceComponentName} to get component name for the intent. Intents should be send with Context#startService
* Please note that service won't start/scan if your application is not foreground, or if Poweramp is not in the foreground, or if Poweramp is not actively playing. */ - public static final class Scanner { - /** + public enum Scanner { + ; + /** * Sent by your app to Poweramp.
* Poweramp Scanner action.

* @@ -1900,8 +1910,9 @@ public static final class Scanner { * Use {@link PowerampAPIHelper#getScannerServiceComponentName} to get component name for the intent. Intents should be send with Context#startService
* Please note that service won't start/scan if your application is not foreground, or if Poweramp is not in the foreground, or if Poweramp is not actively playing. */ - public static class MilkScanner { - /** + public enum MilkScanner { + ; + /** * Sent by your app to Poweramp. Should be sent to {@link PowerampAPIHelper#getMilkScannerServiceComponentName} service via startService (deprecated), * or (since 868) to {@link #API_ACTIVITY_NAME} via startActivity or {@link #API_RECEIVER_NAME} via sendBroadcast
* Extras:
@@ -1936,8 +1947,9 @@ public static class MilkScanner { * * @since 948 */ - public static class Lyrics { - /** + public enum Lyrics { + ; + /** * Sent by Poweramp to your app when lyrics are required for the track.
* Sent, for example, when track has no lyrics, but lyrics mode is enabled, or * when user explicitly requesting the lyrics for a track.

@@ -2020,8 +2032,9 @@ public static class Lyrics { /** * Settings related actions */ - public static class Settings { - /** + public enum Settings { + ; + /** * Poweramp settings activity */ public static final String ACTIVITY_SETTINGS = PowerampAPI.ACTIVITY_SETTINGS; @@ -2139,8 +2152,9 @@ public static class Settings { public static class Preferences { } - public static class PreferencesConsts { - /** + public enum PreferencesConsts { + ; + /** * Don't show vis
*/ public static final int VIS_MODE_VIS_NONE = 0; @@ -2176,7 +2190,7 @@ public static class PreferencesConsts { */ @SuppressWarnings("deprecation") @Deprecated - public static final ComponentName PLAYER_SERVICE_COMPONENT_NAME = new ComponentName(PACKAGE_NAME, PLAYER_SERVICE_NAME); + public static final ComponentName PLAYER_SERVICE_COMPONENT_NAME = new ComponentName(PowerampAPI.PACKAGE_NAME, PowerampAPI.PLAYER_SERVICE_NAME); /** * @return ready to use Intent for Poweramp service @@ -2185,7 +2199,7 @@ public static class PreferencesConsts { @SuppressWarnings("deprecation") @Deprecated public static Intent newAPIIntent() { - return new Intent(ACTION_API_COMMAND).setComponent(PLAYER_SERVICE_COMPONENT_NAME); + return new Intent(PowerampAPI.ACTION_API_COMMAND).setComponent(PowerampAPI.PLAYER_SERVICE_COMPONENT_NAME); } /** @@ -2421,8 +2435,9 @@ public static Intent newAPIIntent() { * @deprecated use ACTION_STATUS_CHANGED */ @Deprecated - public static final class Status { - /** + public enum Status { + ; + /** * STATUS_CHANGED status value - track has been started to play or has been paused.
* Note that Poweramp will start track immediately into this state when it's just loaded to avoid STARTED => PAUSED transition.
* Additional extras - deprecated since 790 - not sent anymore:
diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPIHelper.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPIHelper.java index b2a8670d..19ddc11c 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPIHelper.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/PowerampAPIHelper.java @@ -37,8 +37,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import org.eclipse.jdt.annotation.Nullable; -public class PowerampAPIHelper { - private static final String TAG = "PowerampAPIHelper"; +public enum PowerampAPIHelper { + ; + private static final String TAG = "PowerampAPIHelper"; private static final boolean LOG = false; /** Used to test PA vs older service starting appropach */ private static final boolean DEBUG_ALWAYS_SEND_TO_SERVICE = false; @@ -57,12 +58,12 @@ public class PowerampAPIHelper { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp package name or null if it's not installed
*/ - public static String getPowerampPackageName(Context context) { - String pak = sPowerampPak; - if(pak == null) { - ComponentName componentName = getPlayerServiceComponentNameImpl(context); - if(componentName != null) { - pak = sPowerampPak = componentName.getPackageName(); + public static String getPowerampPackageName(final Context context) { + String pak = PowerampAPIHelper.sPowerampPak; + if(null == pak) { + final ComponentName componentName = PowerampAPIHelper.getPlayerServiceComponentNameImpl(context); + if(null != componentName) { + pak = PowerampAPIHelper.sPowerampPak = componentName.getPackageName(); } } return pak; @@ -74,20 +75,20 @@ public static String getPowerampPackageName(Context context) { * @deprecated use {@link #getApiReceiverComponentName(Context)} */ @Deprecated - public static ComponentName getPlayerServiceComponentName(Context context) { - return getPlayerServiceComponentNameImpl(context); + public static ComponentName getPlayerServiceComponentName(final Context context) { + return PowerampAPIHelper.getPlayerServiceComponentNameImpl(context); } - private static ComponentName getPlayerServiceComponentNameImpl(Context context) { - ComponentName componentName = sPowerampPSComponentName; - if(componentName == null) { + private static ComponentName getPlayerServiceComponentNameImpl(final Context context) { + ComponentName componentName = PowerampAPIHelper.sPowerampPSComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.ACTION_API_COMMAND), 0); - if(info != null && info.serviceInfo != null) { - componentName = sPowerampPSComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + final ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.ACTION_API_COMMAND), 0); + if(null != info && null != info.serviceInfo) { + componentName = PowerampAPIHelper.sPowerampPSComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } } return componentName; @@ -97,16 +98,16 @@ private static ComponentName getPlayerServiceComponentNameImpl(Context context) * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp Media Browser Service component name, or null if not installed */ - public static ComponentName getBrowserServiceComponentName(Context context) { - ComponentName componentName = sBrowserServiceComponentName; - if(componentName == null) { + public static ComponentName getBrowserServiceComponentName(final Context context) { + ComponentName componentName = PowerampAPIHelper.sBrowserServiceComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent("android.media.browse.MediaBrowserService").setPackage(getPowerampPackageName(context)), 0); - if(info != null && info.serviceInfo != null) { - componentName = sBrowserServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + final ResolveInfo info = context.getPackageManager().resolveService(new Intent("android.media.browse.MediaBrowserService").setPackage(PowerampAPIHelper.getPowerampPackageName(context)), 0); + if(null != info && null != info.serviceInfo) { + componentName = PowerampAPIHelper.sBrowserServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } } return componentName; @@ -116,16 +117,16 @@ public static ComponentName getBrowserServiceComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp Media Browser Service component name, or null if not installed */ - public static ComponentName getScannerServiceComponentName(Context context) { - ComponentName componentName = sScanServiceComponentName; - if(componentName == null) { + public static ComponentName getScannerServiceComponentName(final Context context) { + ComponentName componentName = PowerampAPIHelper.sScanServiceComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS).setPackage(getPowerampPackageName(context)), 0); - if(info != null && info.serviceInfo != null) { - componentName = sScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + final ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS).setPackage(PowerampAPIHelper.getPowerampPackageName(context)), 0); + if(null != info && null != info.serviceInfo) { + componentName = PowerampAPIHelper.sScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } } return componentName; @@ -135,16 +136,16 @@ public static ComponentName getScannerServiceComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp milk scanner service component name, or null if not installed */ - public static ComponentName getMilkScannerServiceComponentName(Context context) { - ComponentName componentName = sMilkScanServiceComponentName; - if(componentName == null) { + public static ComponentName getMilkScannerServiceComponentName(final Context context) { + ComponentName componentName = PowerampAPIHelper.sMilkScanServiceComponentName; + if(null == componentName) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.MilkScanner.ACTION_SCAN).setPackage(getPowerampPackageName(context)), 0); - if(info != null && info.serviceInfo != null) { - componentName = sMilkScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); + final ResolveInfo info = context.getPackageManager().resolveService(new Intent(PowerampAPI.MilkScanner.ACTION_SCAN).setPackage(PowerampAPIHelper.getPowerampPackageName(context)), 0); + if(null != info && null != info.serviceInfo) { + componentName = PowerampAPIHelper.sMilkScanServiceComponentName = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } } return componentName; @@ -154,12 +155,12 @@ public static ComponentName getMilkScannerServiceComponentName(Context context) * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp API receiver component name, or null if not installed */ - public static ComponentName getApiReceiverComponentName(Context context) { - ComponentName componentName = sApiReceiverComponentName; - if(componentName == null) { - String pak = getPowerampPackageName(context); - if(pak != null) { - componentName = sApiReceiverComponentName = new ComponentName(pak, PowerampAPI.API_RECEIVER_NAME); + public static ComponentName getApiReceiverComponentName(final Context context) { + ComponentName componentName = PowerampAPIHelper.sApiReceiverComponentName; + if(null == componentName) { + final String pak = PowerampAPIHelper.getPowerampPackageName(context); + if(null != pak) { + componentName = PowerampAPIHelper.sApiReceiverComponentName = new ComponentName(pak, PowerampAPI.API_RECEIVER_NAME); } } return componentName; @@ -170,12 +171,12 @@ public static ComponentName getApiReceiverComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp API activity component name, or null if not installed */ - public static ComponentName getApiActivityComponentName(Context context) { - ComponentName componentName = sApiActivityComponentName; - if(componentName == null) { - String pak = getPowerampPackageName(context); - if(pak != null) { - componentName = sApiActivityComponentName = new ComponentName(pak, PowerampAPI.API_ACTIVITY_NAME); + public static ComponentName getApiActivityComponentName(final Context context) { + ComponentName componentName = PowerampAPIHelper.sApiActivityComponentName; + if(null == componentName) { + final String pak = PowerampAPIHelper.getPowerampPackageName(context); + if(null != pak) { + componentName = PowerampAPIHelper.sApiActivityComponentName = new ComponentName(pak, PowerampAPI.API_ACTIVITY_NAME); } } return componentName; @@ -185,26 +186,26 @@ public static ComponentName getApiActivityComponentName(Context context) { * THREADING: can be called from any thread, though double initialization is possible, but it's OK * @return resolved and cached Poweramp build number
*/ - public static int getPowerampBuild(Context context) { - if(sPowerampBuild == 0) { - String pak = getPowerampPackageName(context); - if(pak != null) { + public static int getPowerampBuild(final Context context) { + if(0 == sPowerampBuild) { + final String pak = PowerampAPIHelper.getPowerampPackageName(context); + if(null != pak) { try { - PackageInfo pi = context.getPackageManager().getPackageInfo(pak, 0); - sPowerampBuild = pi.versionCode > 1000 ? pi.versionCode / 1000 : pi.versionCode; - } catch(Throwable th) { - Log.e(TAG, "", th); + final PackageInfo pi = context.getPackageManager().getPackageInfo(pak, 0); + PowerampAPIHelper.sPowerampBuild = 1000 < pi.versionCode ? pi.versionCode / 1000 : pi.versionCode; + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } } } - return sPowerampBuild; + return PowerampAPIHelper.sPowerampBuild; } /** * THREADING: can be called from any thread
* @return intent to send with sendPAIntent */ - public static Intent newAPIIntent(Context context) { + public static Intent newAPIIntent(final Context context) { return new Intent(PowerampAPI.ACTION_API_COMMAND); } @@ -215,8 +216,8 @@ public static Intent newAPIIntent(Context context) { * THREADING: can be called from any thread
* @return true if intent was successfully sent, false otherwise */ - public static boolean sendPAIntent(Context context, Intent intent) { - return sendPAIntent(context, intent, false); + public static boolean sendPAIntent(final Context context, final Intent intent) { + return PowerampAPIHelper.sendPAIntent(context, intent, false); } /** @@ -226,14 +227,14 @@ public static boolean sendPAIntent(Context context, Intent intent) { * @param sendToActivity if true, we're sending intent to the activity (build 862+) * @return true if intent was successfully sent, false otherwise */ - public static boolean sendPAIntent(Context context, Intent intent, boolean sendToActivity) { + public static boolean sendPAIntent(final Context context, final Intent intent, final boolean sendToActivity) { try { - int buildNum = getPowerampBuild(context); + final int buildNum = PowerampAPIHelper.getPowerampBuild(context); intent.putExtra(PowerampAPI.EXTRA_PACKAGE, context.getPackageName()); - if(DEBUG_ALWAYS_SEND_TO_SERVICE) { - intent.setComponent(getPlayerServiceComponentNameImpl(context)); - if(Build.VERSION.SDK_INT >= 26) { + if(PowerampAPIHelper.DEBUG_ALWAYS_SEND_TO_SERVICE) { + intent.setComponent(PowerampAPIHelper.getPlayerServiceComponentNameImpl(context)); + if(26 <= Build.VERSION.SDK_INT) { context.startForegroundService(intent); } else { context.startService(intent); @@ -241,34 +242,34 @@ public static boolean sendPAIntent(Context context, Intent intent, boolean sendT return true; } - if(sendToActivity && buildNum >= 862) { - intent.setComponent(getApiActivityComponentName(context)); + if(sendToActivity && 862 <= buildNum) { + intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(context)); if(!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); - } else if(buildNum >= 855) { - intent.setComponent(getApiReceiverComponentName(context)); + } else if(855 <= buildNum) { + intent.setComponent(PowerampAPIHelper.getApiReceiverComponentName(context)); context.sendBroadcast(intent); } else { - intent.setComponent(getPlayerServiceComponentNameImpl(context)); - if(Build.VERSION.SDK_INT >= 26) { + intent.setComponent(PowerampAPIHelper.getPlayerServiceComponentNameImpl(context)); + if(26 <= Build.VERSION.SDK_INT) { context.startForegroundService(intent); } else { context.startService(intent); } } return true; - } catch(Exception ex) { - Log.e(TAG, "intent=" + intent, ex); + } catch(final Exception ex) { + Log.e(PowerampAPIHelper.TAG, "intent=" + intent, ex); return false; } } @Deprecated - public static void startPAServiceOld(Context context, Intent intent) { - intent.setComponent(getPlayerServiceComponentNameImpl(context)); - if(Build.VERSION.SDK_INT >= 26) { + public static void startPAServiceOld(final Context context, final Intent intent) { + intent.setComponent(PowerampAPIHelper.getPlayerServiceComponentNameImpl(context)); + if(26 <= Build.VERSION.SDK_INT) { context.startForegroundService(intent); } else { context.startService(intent); @@ -278,47 +279,47 @@ public static void startPAServiceOld(Context context, Intent intent) { // WARNING: openFileDescriptor() will return the original image right from the track loaded in Poweramp or // a cached image file. The later is more or less under control in terms of size, though, that can be in-folder user provided image without any limits. // As for embedded album art, the resulting bitmap can be any size. Poweramp has some upper limits on embed album art, still the decoded image can be very large. - public static @Nullable Bitmap getAlbumArt(Context context, @Nullable Bundle track, int subsampleWidth, int subsampleHeight) { - if(track == null) { - if(LOG) Log.e(TAG, "getAlbumArt !track"); + public static @Nullable Bitmap getAlbumArt(final Context context, @Nullable final Bundle track, final int subsampleWidth, final int subsampleHeight) { + if(null == track) { + if(PowerampAPIHelper.LOG) Log.e(PowerampAPIHelper.TAG, "getAlbumArt !track"); return null; } - Uri aaUri = PowerampAPI.AA_ROOT_URI.buildUpon().appendEncodedPath("files").appendEncodedPath(Long.toString(track.getLong(PowerampAPI.Track.REAL_ID))).build(); + final Uri aaUri = PowerampAPI.AA_ROOT_URI.buildUpon().appendEncodedPath("files").appendEncodedPath(Long.toString(track.getLong(PowerampAPI.Track.REAL_ID))).build(); - try(ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(aaUri, "r")) { - if(pfd != null) { - BitmapFactory.Options opts = new BitmapFactory.Options(); + try(final ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(aaUri, "r")) { + if(null != pfd) { + final BitmapFactory.Options opts = new BitmapFactory.Options(); // If this pfd is pipe, we can't reuse it for decoding, so don't do the subsample then - if(pfd.getStatSize() > 0) { + if(0 < pfd.getStatSize()) { // Get original bitmap size opts.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, opts); // Calculate subsample and load subsampled image opts.inJustDecodeBounds = false; - if(subsampleWidth > 0 && subsampleHeight > 0) { - opts.inSampleSize = calcSubsample(subsampleWidth, subsampleHeight, opts.outWidth, opts.outHeight); // Subsamples images up to 2047x2047, should be safe, though this is up to 16mb per bitmap + if(0 < subsampleWidth && 0 < subsampleHeight) { + opts.inSampleSize = PowerampAPIHelper.calcSubsample(subsampleWidth, subsampleHeight, opts.outWidth, opts.outHeight); // Subsamples images up to 2047x2047, should be safe, though this is up to 16mb per bitmap } } - Bitmap b = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, opts); + final Bitmap b = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, opts); - if(LOG) Log.e(TAG, "getAlbumArt aaUri=" + aaUri + " b=" + b); - if(LOG && b != null) - Log.e(TAG, "getAlbumArt w=" + b.getWidth() + " h=" + b.getHeight()); + if(PowerampAPIHelper.LOG) Log.e(PowerampAPIHelper.TAG, "getAlbumArt aaUri=" + aaUri + " b=" + b); + if(PowerampAPIHelper.LOG && null != b) + Log.e(PowerampAPIHelper.TAG, "getAlbumArt w=" + b.getWidth() + " h=" + b.getHeight()); return b; - } else if(LOG) Log.e(TAG, "getAlbumArt no pfd for aaUri=" + aaUri); + } else if(PowerampAPIHelper.LOG) Log.e(PowerampAPIHelper.TAG, "getAlbumArt no pfd for aaUri=" + aaUri); - } catch(FileNotFoundException ex) { + } catch(final FileNotFoundException ex) { // OK - if(LOG) Log.e(TAG, "getAlbumArt aaUri=" + aaUri, ex); + if(PowerampAPIHelper.LOG) Log.e(PowerampAPIHelper.TAG, "getAlbumArt aaUri=" + aaUri, ex); - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(PowerampAPIHelper.TAG, "", th); } @@ -326,7 +327,7 @@ public static void startPAServiceOld(Context context, Intent intent) { } // NOTE: maxW/maxH is not actual max, as we just subsample. Output image size will be up to maxW(H)*2 - 1 - private static int calcSubsample(final int maxW, final int maxH, final int outWidth, final int outHeight) { + private static int calcSubsample(int maxW, int maxH, int outWidth, int outHeight) { int sampleSize = 1; int nextWidth = outWidth >> 1; int nextHeight = outHeight >> 1; diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RemoteTrackTime.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RemoteTrackTime.java index 8aa884cf..08fd149d 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RemoteTrackTime.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RemoteTrackTime.java @@ -54,96 +54,96 @@ public class RemoteTrackTime { public interface TrackTimeListener { - public void onTrackDurationChanged(int duration); - public void onTrackPositionChanged(int position); + void onTrackDurationChanged(int duration); + void onTrackPositionChanged(int position); } TrackTimeListener mTrackTimeListener; - public RemoteTrackTime(Context context) { - mContext = context; + public RemoteTrackTime(final Context context) { + this.mContext = context; } public void registerAndLoadStatus() { - IntentFilter filter = new IntentFilter(PowerampAPI.ACTION_TRACK_POS_SYNC); - mContext.registerReceiver(mTrackPosSyncReceiver, filter); + final IntentFilter filter = new IntentFilter(PowerampAPI.ACTION_TRACK_POS_SYNC); + this.mContext.registerReceiver(this.mTrackPosSyncReceiver, filter); - PowerampAPIHelper.sendPAIntent(mContext, new Intent(PowerampAPI.ACTION_API_COMMAND) + PowerampAPIHelper.sendPAIntent(this.mContext, new Intent(PowerampAPI.ACTION_API_COMMAND) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.POS_SYNC)); - if(mPlaying) { - mHandler.removeCallbacks(mTickRunnable); - mHandler.postDelayed(mTickRunnable, 0); + if(this.mPlaying) { + this.mHandler.removeCallbacks(this.mTickRunnable); + this.mHandler.postDelayed(this.mTickRunnable, 0); } } public void unregister() { try { - mContext.unregisterReceiver(mTrackPosSyncReceiver); - } catch(Exception ignored) { } - mHandler.removeCallbacks(mTickRunnable); + this.mContext.unregisterReceiver(this.mTrackPosSyncReceiver); + } catch(final Exception ignored) { } + this.mHandler.removeCallbacks(this.mTickRunnable); } private final @NonNull BroadcastReceiver mTrackPosSyncReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - int pos = intent.getIntExtra(PowerampAPI.Track.POSITION, 0); - if(LOG) Log.w(TAG, "mTrackPosSyncReceiver sync=" + pos); - updateTrackPosition(pos); + public void onReceive(final Context context, final Intent intent) { + final int pos = intent.getIntExtra(PowerampAPI.Track.POSITION, 0); + if(RemoteTrackTime.LOG) Log.w(RemoteTrackTime.TAG, "mTrackPosSyncReceiver sync=" + pos); + RemoteTrackTime.this.updateTrackPosition(pos); } }; - public void setTrackTimeListener(TrackTimeListener l) { - mTrackTimeListener = l; + public void setTrackTimeListener(final TrackTimeListener l) { + this.mTrackTimeListener = l; } - public void updateTrackDuration(int duration) { - if(mTrackTimeListener != null) { - mTrackTimeListener.onTrackDurationChanged(duration); + public void updateTrackDuration(final int duration) { + if(null != mTrackTimeListener) { + this.mTrackTimeListener.onTrackDurationChanged(duration); } } - public void updateTrackPosition(int position) { - mPosition = position; - if(LOG) Log.w(TAG, "updateTrackPosition mPosition=>" + mPosition); - if(mPlaying) { - mStartTimeMs = System.currentTimeMillis(); - mStartPosition = mPosition; + public void updateTrackPosition(final int position) { + this.mPosition = position; + if(RemoteTrackTime.LOG) Log.w(RemoteTrackTime.TAG, "updateTrackPosition mPosition=>" + this.mPosition); + if(this.mPlaying) { + this.mStartTimeMs = System.currentTimeMillis(); + this.mStartPosition = this.mPosition; } - if(mTrackTimeListener != null) { - mTrackTimeListener.onTrackPositionChanged(position); + if(null != mTrackTimeListener) { + this.mTrackTimeListener.onTrackPositionChanged(position); } } protected final Runnable mTickRunnable = new Runnable() { @Override public void run() { - mPosition = (int)(System.currentTimeMillis() - mStartTimeMs + 500) / 1000 + mStartPosition; - if(LOG) Log.w(TAG, "mTickRunnable mPosition=" + mPosition); - if(mTrackTimeListener != null) { - mTrackTimeListener.onTrackPositionChanged(mPosition); + RemoteTrackTime.this.mPosition = (int)(System.currentTimeMillis() - RemoteTrackTime.this.mStartTimeMs + 500) / 1000 + RemoteTrackTime.this.mStartPosition; + if(RemoteTrackTime.LOG) Log.w(RemoteTrackTime.TAG, "mTickRunnable mPosition=" + RemoteTrackTime.this.mPosition); + if(null != mTrackTimeListener) { + RemoteTrackTime.this.mTrackTimeListener.onTrackPositionChanged(RemoteTrackTime.this.mPosition); } - mHandler.removeCallbacks(mTickRunnable); - mHandler.postDelayed(mTickRunnable, UPDATE_DELAY); + RemoteTrackTime.this.mHandler.removeCallbacks(RemoteTrackTime.this.mTickRunnable); + RemoteTrackTime.this.mHandler.postDelayed(RemoteTrackTime.this.mTickRunnable, RemoteTrackTime.UPDATE_DELAY); } }; public void startSongProgress() { - if(!mPlaying) { - mStartTimeMs = System.currentTimeMillis(); - mStartPosition = mPosition; - mHandler.removeCallbacks(mTickRunnable); - mHandler.postDelayed(mTickRunnable, UPDATE_DELAY); - mPlaying = true; + if(!this.mPlaying) { + this.mStartTimeMs = System.currentTimeMillis(); + this.mStartPosition = this.mPosition; + this.mHandler.removeCallbacks(this.mTickRunnable); + this.mHandler.postDelayed(this.mTickRunnable, RemoteTrackTime.UPDATE_DELAY); + this.mPlaying = true; } } public void stopSongProgress() { - if(mPlaying) { - mHandler.removeCallbacks(mTickRunnable); - mPlaying = false; + if(this.mPlaying) { + this.mHandler.removeCallbacks(this.mTickRunnable); + this.mPlaying = false; } } } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RouterConsts.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RouterConsts.java index ad227c44..819ffc34 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RouterConsts.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/RouterConsts.java @@ -28,65 +28,65 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface RouterConsts { // Sync with plugininterface-output.h - public static final int DEVICE_HEADSET = 0; - public static final int DEVICE_SPEAKER = 1; - public static final int DEVICE_BT = 2; - public static final int DEVICE_USB = 3; - public static final int DEVICE_OTHER = 4; - public static final int DEVICE_CHROMECAST = 5; + int DEVICE_HEADSET = 0; + int DEVICE_SPEAKER = 1; + int DEVICE_BT = 2; + int DEVICE_USB = 3; + int DEVICE_OTHER = 4; + int DEVICE_CHROMECAST = 5; // 6 - public static final int DEVICE_UNKNOWN = 0xFF; + int DEVICE_UNKNOWN = 0xFF; - public static final int DEVICE_COUNT = 6; - public static final int DEVICE_SAFE_DEFAULT = DEVICE_HEADSET; + int DEVICE_COUNT = 6; + int DEVICE_SAFE_DEFAULT = RouterConsts.DEVICE_HEADSET; - public static final @NonNull String DEVICE_NAME_HEADSET = "headset"; - public static final @NonNull String DEVICE_NAME_SPEAKER = "speaker"; - public static final @NonNull String DEVICE_NAME_BT = "bt"; - public static final @NonNull String DEVICE_NAME_USB = "usb"; - public static final @NonNull String DEVICE_NAME_OTHER = "other"; - public static final @NonNull String DEVICE_NAME_CHROMECAST = "chromecast"; + @NonNull String DEVICE_NAME_HEADSET = "headset"; + @NonNull String DEVICE_NAME_SPEAKER = "speaker"; + @NonNull String DEVICE_NAME_BT = "bt"; + @NonNull String DEVICE_NAME_USB = "usb"; + @NonNull String DEVICE_NAME_OTHER = "other"; + @NonNull String DEVICE_NAME_CHROMECAST = "chromecast"; @TargetApi(23) - public static int toAndroidDeviceType(int device) { + static int toAndroidDeviceType(final int device) { switch(device) { default: - case DEVICE_HEADSET: + case RouterConsts.DEVICE_HEADSET: return AudioDeviceInfo.TYPE_WIRED_HEADSET; // 3 - case DEVICE_SPEAKER: + case RouterConsts.DEVICE_SPEAKER: return AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; // 2 - case DEVICE_BT: + case RouterConsts.DEVICE_BT: return AudioDeviceInfo.TYPE_BLUETOOTH_A2DP; // 8 - case DEVICE_USB: + case RouterConsts.DEVICE_USB: return AudioDeviceInfo.TYPE_USB_DEVICE; // 11 - case DEVICE_CHROMECAST: + case RouterConsts.DEVICE_CHROMECAST: return AudioDeviceInfo.TYPE_IP; // 20 } } /** @return true if the device is a valid known device (excluding {@link #DEVICE_UNKNOWN}) */ - public static boolean isValidKnownDevice(int device) { - return device >= 0 && device < DEVICE_COUNT; + static boolean isValidKnownDevice(final int device) { + return 0 <= device && DEVICE_COUNT > device; } - public static int getDeviceId(@Nullable String device) { - if(device == null) { + static int getDeviceId(@Nullable final String device) { + if(null == device) { return -1; } switch(device) { - case DEVICE_NAME_HEADSET: - return DEVICE_HEADSET; - case DEVICE_NAME_SPEAKER: - return DEVICE_SPEAKER; - case DEVICE_NAME_BT: - return DEVICE_BT; - case DEVICE_NAME_USB: - return DEVICE_USB; - case DEVICE_NAME_OTHER: - return DEVICE_OTHER; - case DEVICE_NAME_CHROMECAST: - return DEVICE_CHROMECAST; + case RouterConsts.DEVICE_NAME_HEADSET: + return RouterConsts.DEVICE_HEADSET; + case RouterConsts.DEVICE_NAME_SPEAKER: + return RouterConsts.DEVICE_SPEAKER; + case RouterConsts.DEVICE_NAME_BT: + return RouterConsts.DEVICE_BT; + case RouterConsts.DEVICE_NAME_USB: + return RouterConsts.DEVICE_USB; + case RouterConsts.DEVICE_NAME_OTHER: + return RouterConsts.DEVICE_OTHER; + case RouterConsts.DEVICE_NAME_CHROMECAST: + return RouterConsts.DEVICE_CHROMECAST; default: return -1; } @@ -94,25 +94,25 @@ public static int getDeviceId(@Nullable String device) { // NOTE: used as pref part // REVISIT: refactor this and following statics into a helper? - public static @NonNull String getDeviceName(int device) { + static @NonNull String getDeviceName(final int device) { switch(device) { - case DEVICE_HEADSET: - return DEVICE_NAME_HEADSET; + case RouterConsts.DEVICE_HEADSET: + return RouterConsts.DEVICE_NAME_HEADSET; - case DEVICE_SPEAKER: - return DEVICE_NAME_SPEAKER; + case RouterConsts.DEVICE_SPEAKER: + return RouterConsts.DEVICE_NAME_SPEAKER; - case DEVICE_BT: - return DEVICE_NAME_BT; + case RouterConsts.DEVICE_BT: + return RouterConsts.DEVICE_NAME_BT; - case DEVICE_USB: - return DEVICE_NAME_USB; + case RouterConsts.DEVICE_USB: + return RouterConsts.DEVICE_NAME_USB; - case DEVICE_OTHER: - return DEVICE_NAME_OTHER; + case RouterConsts.DEVICE_OTHER: + return RouterConsts.DEVICE_NAME_OTHER; - case DEVICE_CHROMECAST: - return DEVICE_NAME_CHROMECAST; + case RouterConsts.DEVICE_CHROMECAST: + return RouterConsts.DEVICE_NAME_CHROMECAST; default: return "Unknown_" + device; diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TableDefs.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TableDefs.java index 576658d9..b709ebfa 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TableDefs.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TableDefs.java @@ -20,131 +20,129 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING package com.maxmpz.poweramp.player; -import com.maxmpz.poweramp.player.PowerampAPI.Track.FileType; -import com.maxmpz.poweramp.player.PowerampAPI.Track.TagStatus; import org.eclipse.jdt.annotation.NonNull; public interface TableDefs { /** * Alias used for category. Useful when query is actually a multi table join */ - public static final @NonNull String CATEGORY_ALIAS = "cat"; + @NonNull String CATEGORY_ALIAS = "cat"; /** * Id used for all "unknown" categories. Also see {@link PowerampAPI#NO_ID} */ - public static final long UNKNOWN_ID = 1000L; + long UNKNOWN_ID = 1000L; /** * Alias used for category aliased table _id */ - public static final @NonNull String CATEGORY_ALIAS_ID = CATEGORY_ALIAS + "._id"; + @NonNull String CATEGORY_ALIAS_ID = TableDefs.CATEGORY_ALIAS + "._id"; /** * Tracks */ - public interface Files { + interface Files { /** Special value for {@link #TRACK_NUMBER} - means no valid track number exists for the given track */ - public static final int INVALID_TRACK_NUMBER = 10000; + int INVALID_TRACK_NUMBER = 10000; - public static final @NonNull String TABLE = "folder_files"; + @NonNull String TABLE = "folder_files"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Files.TABLE + "._id"; /** * Short filename
* TEXT */ - public static final @NonNull String NAME = TABLE + ".name"; + @NonNull String NAME = Files.TABLE + ".name"; /** * Track number extracted from tag or filename. May include disc number (if >= 2) as thousands (2001, 2002, etc.). Can be {@link #INVALID_TRACK_NUMBER}.
* Used for sorting
* INTEGER */ - public static final @NonNull String TRACK_NUMBER = "track_number"; + @NonNull String TRACK_NUMBER = "track_number"; /** * Track number for display purposes (since 858), prior 858 just track number from track tags. 0 or NULL if no track tag exists.
* Never includes disc number (since 858)
* INTEGER */ - public static final @NonNull String TRACK_TAG = "track_tag"; + @NonNull String TRACK_TAG = "track_tag"; /** * Track disc or 0 if no such tag exists
* INTEGER * @since 859
*/ - public static final @NonNull String DISC = "disc"; + @NonNull String DISC = "disc"; /** * Track name without number. For streams - this is name of stream, if available
* TEXT */ - public static final @NonNull String NAME_WITHOUT_NUMBER = "name_without_number"; + @NonNull String NAME_WITHOUT_NUMBER = "name_without_number"; /** * One of the TAG_* constants
* INTEGER * @see com.maxmpz.poweramp.player.PowerampAPI.Track.TagStatus */ - public static final @NonNull String TAG_STATUS = "tag_status"; + @NonNull String TAG_STATUS = "tag_status"; /** * Parent folder id
* INTEGER */ - public static final @NonNull String FOLDER_ID = "folder_id"; + @NonNull String FOLDER_ID = "folder_id"; /** * Title tag
* NOTE: important to have it w/o table name for the header-enabled compound selects
* TEXT */ - public static final @NonNull String TITLE_TAG = "title_tag"; + @NonNull String TITLE_TAG = "title_tag"; /** * NOTE: non-null for streams only
* TEXT */ - public static final @NonNull String ALBUM_TAG = "album_tag"; + @NonNull String ALBUM_TAG = "album_tag"; /** * NOTE: non-null for streams only
* TEXT */ - public static final @NonNull String ARTIST_TAG = "artist_tag"; + @NonNull String ARTIST_TAG = "artist_tag"; /** * Duration in milliseconds
* INTEGER */ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Files.TABLE + ".duration"; /** * Time of update in epoch seconds
* INTEGER */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + @NonNull String UPDATED_AT = Files.TABLE + ".updated_at"; /** * One of the file types - {@link PowerampAPI.Track.FileType}
*/ - public static final @NonNull String FILE_TYPE = "file_type"; + @NonNull String FILE_TYPE = "file_type"; /** * Milliseconds, updated when track started
* INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Files.TABLE + ".played_at"; /** * Milliseconds, updated with play start time (=played_at) when and only if track is counted as played
* INTEGER * @since 900 */ - public static final @NonNull String PLAYED_FULLY_AT = TABLE + ".played_fully_at"; + @NonNull String PLAYED_FULLY_AT = Files.TABLE + ".played_fully_at"; /** * This is the file last modified time - mtime (for the most Android variants).
@@ -152,97 +150,97 @@ public interface Files { * Seconds
* INTEGER */ - public static final @NonNull String FILE_CREATED_AT = "file_created_at"; + @NonNull String FILE_CREATED_AT = "file_created_at"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Files.TABLE + ".aa_status"; /** * INTEGER */ - public static final @NonNull String RATING = "rating"; + @NonNull String RATING = "rating"; /** * INTEGER */ - public static final @NonNull String PLAYED_TIMES = TABLE + ".played_times"; + @NonNull String PLAYED_TIMES = Files.TABLE + ".played_times"; /** * INTEGER */ - public static final @NonNull String ALBUM_ID = TABLE + ".album_id"; + @NonNull String ALBUM_ID = Files.TABLE + ".album_id"; /** * INTEGER */ - public static final @NonNull String ARTIST_ID = TABLE + ".artist_id"; + @NonNull String ARTIST_ID = Files.TABLE + ".artist_id"; /** * INTEGER */ - public static final @NonNull String ALBUM_ARTIST_ID = TABLE + ".album_artist_id"; + @NonNull String ALBUM_ARTIST_ID = Files.TABLE + ".album_artist_id"; /** * INTEGER */ - public static final @NonNull String COMPOSER_ID = TABLE + ".composer_id"; + @NonNull String COMPOSER_ID = Files.TABLE + ".composer_id"; /** * INTEGER */ - public static final @NonNull String YEAR = TABLE + ".year"; + @NonNull String YEAR = Files.TABLE + ".year"; /** * Cue offset milliseconds
* INTEGER */ - public static final @NonNull String OFFSET_MS = TABLE + ".offset_ms"; + @NonNull String OFFSET_MS = Files.TABLE + ".offset_ms"; /** * If non-null - this is cue "source" (big uncut image) file with that given virtual folder id
* NOTE: enforces 1-1 between source files and cues. No multiple cues per single image thus possible
* INTEGER */ - public static final @NonNull String CUE_FOLDER_ID = "cue_folder_id"; + @NonNull String CUE_FOLDER_ID = "cue_folder_id"; /** * First seen time
* Seconds
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Files.TABLE + ".created_at"; /** * Wave scan data
* byte[] blob, nullable */ - public static final @NonNull String WAVE = "wave"; + @NonNull String WAVE = "wave"; /** * TEXT */ - public static final @NonNull String META = TABLE + ".meta"; + @NonNull String META = Files.TABLE + ".meta"; /** * Last played position in milliseconds
* INTEGER */ - public static final @NonNull String LAST_POS = "last_pos"; + @NonNull String LAST_POS = "last_pos"; /** * INTEGER */ - public static final @NonNull String SHUFFLE_ORDER = TABLE + ".shuffle_order"; + @NonNull String SHUFFLE_ORDER = Files.TABLE + ".shuffle_order"; /** * 1 if this item (most probably stream track) was manually added and shouldn't be removed by rescans
* INTEGER (boolean) * @since 857
*/ - public static final @NonNull String USER_ADDED = TABLE + ".user_added"; + @NonNull String USER_ADDED = Files.TABLE + ".user_added"; /** * Optional http(s) URL pointing to the target track. If exists, this will be used @@ -250,7 +248,7 @@ public interface Files { * Can be {@link TrackProviderConsts#DYNAMIC_URL}
* TEXT */ - public static final @NonNull String URL = TABLE + ".url"; + @NonNull String URL = Files.TABLE + ".url"; /** * Optional full path to the file. This file_path always overrides parent folder path + filename. Used for the cases @@ -260,40 +258,42 @@ public interface Files { * TEXT * @since 862 */ - public static final @NonNull String FILE_PATH = TABLE + ".file_path"; + @NonNull String FILE_PATH = Files.TABLE + ".file_path"; /** * Optional bitrate of the file. Currently set only for the provider tracks if provided in the appropiate metadata
* INTEGER * @since 862 */ - public static final @NonNull String BIT_RATE = TABLE + ".bit_rate"; + @NonNull String BIT_RATE = Files.TABLE + ".bit_rate"; /** * Full path. Works only if the query is joined with the folders, otherwise this may fail
* TEXT */ - public static final @NonNull String FULL_PATH = "COALESCE(" + FILE_PATH + ","+ Folders.PATH + "||" + NAME + "," + NAME + ")"; + @NonNull String FULL_PATH = "COALESCE(" + Files.FILE_PATH + ","+ Folders.PATH + "||" + Files.NAME + "," + Files.NAME + ")"; /** * Alternative track number. Currently applied only in Folders/Folders Hierarchy files for track number sorting. May differ for provider tracks, equals track_number for * all other tracks
* INTEGER */ - public static final @NonNull String TRACK_NUMBER_ALT = "track_number_alt"; + @NonNull String TRACK_NUMBER_ALT = "track_number_alt"; /** * @deprecated * @see com.maxmpz.poweramp.player.PowerampAPI.Track.TagStatus#TAG_NOT_SCANNED */ - public static final int TAG_NOT_SCANNED = TagStatus.TAG_NOT_SCANNED; + @Deprecated + int TAG_NOT_SCANNED = PowerampAPI.Track.TagStatus.TAG_NOT_SCANNED; /** * @deprecated * @see com.maxmpz.poweramp.player.PowerampAPI.Track.TagStatus#TAG_SCANNED */ - public static final int TAG_SCANNED = TagStatus.TAG_SCANNED; + @Deprecated + int TAG_SCANNED = PowerampAPI.Track.TagStatus.TAG_SCANNED; /** @@ -301,7 +301,7 @@ public interface Files { * INTEGER NULL * @since 948 */ - public static final @NonNull String LRC_FILES_ID = "lrc_files_id"; + @NonNull String LRC_FILES_ID = "lrc_files_id"; /** * If non-NULL, defines priority for {@link #LRC_FILES_ID}. The higher value is the higher priority. @@ -310,21 +310,21 @@ public interface Files { * INTEGER NOT NULL DEFAULT 0 * @since 948 */ - public static final @NonNull String LRC_FILES_PRIO = "lrc_files_prio"; + @NonNull String LRC_FILES_PRIO = "lrc_files_prio"; /** * 1 if this track is known to have lyrics tag (not necessarily a synchronized lyrics)
* INTEGER NOT NULL (boolean) * @since 948 */ - public static final @NonNull String HAS_LYRICS_TAG = "has_lyrics_tag"; + @NonNull String HAS_LYRICS_TAG = "has_lyrics_tag"; /** * If non-NULL, references cached lyrics entry in {@link CachedLyrics} * INTEGER NULL * @since 948 */ - public static final @NonNull String CACHED_LYRICS_ID = "cached_lyrics_id"; + @NonNull String CACHED_LYRICS_ID = "cached_lyrics_id"; /** * Cached lyrics loading start timestamp
@@ -333,16 +333,16 @@ public interface Files { * INTEGER NULL * @since 948 */ - public static final @NonNull String CACHED_LYRICS_LOADING_STARTED_AT = "cached_lyrics_loading_started_at"; + @NonNull String CACHED_LYRICS_LOADING_STARTED_AT = "cached_lyrics_loading_started_at"; /** * Calculated field
* INTEGER (boolean) */ - public static final @NonNull String HAS_LYRICS = + @NonNull String HAS_LYRICS = // NOTE: avoid matching cached_lyrics_id for stream as stream constantly changes metadata "(has_lyrics_tag OR lrc_files_id IS NOT NULL" + - " OR cached_lyrics_id IS NOT NULL AND cached_lyrics_loading_started_at IS NULL AND file_type!=" + FileType.TYPE_STREAM + + " OR cached_lyrics_id IS NOT NULL AND cached_lyrics_loading_started_at IS NULL AND file_type!=" + PowerampAPI.Track.FileType.TYPE_STREAM + ") AS _has_lyrics"; } @@ -350,22 +350,22 @@ public interface Files { * Contains the single track entry when/if some path is requested to be played and that path is not in Poweramp Music Folders/Library.
* @since 949 this is always a structural copy of folder_files table (with just that one _id={@link PowerampAPI#RAW_TRACK_ID} (-2) entry) */ - public interface RawFiles extends Files { - public static final @NonNull String TABLE = "raw_files"; + interface RawFiles extends Files { + @NonNull String TABLE = "raw_files"; } /** All known Poweramp folders */ - public interface Folders { - public static final @NonNull String TABLE = "folders"; + interface Folders { + @NonNull String TABLE = "folders"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Folders.TABLE + "._id"; /** * Display (label) name of the folder. Can be long for roots (e.g. can include storage description).
* May or may not match actual filesystem folder name
* TEXT */ - public static final @NonNull String NAME = TABLE + ".name"; + @NonNull String NAME = Folders.TABLE + ".name"; /** * (Always) short name of the folder. Always matches actual filesystem folder name
@@ -373,20 +373,20 @@ public interface Folders { * TEXT * @since 828 */ - public static final @NonNull String SHORT_NAME = TABLE + ".short_name"; + @NonNull String SHORT_NAME = Folders.TABLE + ".short_name"; /** * Short path of the parent folder. Always matches parent short_name which is parent actual filesystem folder name
* TEXT */ - public static final @NonNull String PARENT_NAME = TABLE + ".parent_name"; + @NonNull String PARENT_NAME = Folders.TABLE + ".parent_name"; /** * Parent folder display label (which can be much longer than just PARENT_NAME, e.g. include storage description) to display in the UI.
* Corresponds to parent name
* TEXT */ - public static final @NonNull String PARENT_LABEL = TABLE + ".parent_label"; + @NonNull String PARENT_LABEL = Folders.TABLE + ".parent_label"; /** * Full path of the folder
@@ -394,69 +394,69 @@ public interface Folders { * The path has a trailing / * TEXT */ - public static final @NonNull String PATH = "path"; + @NonNull String PATH = "path"; /** * This is the same as path for usual folders, but for the cue virtual folders, this is path + name
* Used for proper folders/subfolders hiearachy sorting and it's ciritcal for correct hieararchy playing/reshuffle
* TEXT */ - public static final @NonNull String SORT_PATH = "sort_path"; + @NonNull String SORT_PATH = "sort_path"; /** * Folder album art/thumb image (short name)
* TEXT */ - public static final @NonNull String THUMB = "thumb"; + @NonNull String THUMB = "thumb"; /** * INTEGER */ - public static final @NonNull String DIR_MODIFIED_AT = TABLE + ".dir_modified_at"; + @NonNull String DIR_MODIFIED_AT = Folders.TABLE + ".dir_modified_at"; /** * Seconds
* INTEGER */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + @NonNull String UPDATED_AT = Folders.TABLE + ".updated_at"; /** * Id of the parent folder or 0 for "root" folders
* INTEGER */ - public static final @NonNull String PARENT_ID = TABLE + ".parent_id"; + @NonNull String PARENT_ID = Folders.TABLE + ".parent_id"; /** * INTEGER */ - public static final @NonNull String IS_CUE = TABLE + ".is_cue"; + @NonNull String IS_CUE = Folders.TABLE + ".is_cue"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Folders.TABLE + ".created_at"; /** * Number of direct child subfolders
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_SUBFOLDERS = TABLE + ".num_subfolders"; + @NonNull String NUM_SUBFOLDERS = Folders.TABLE + ".num_subfolders"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Folders.TABLE + ".num_files"; /** * Number of tracks in this category, including cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Folders.TABLE + ".num_all_files"; /** * Number of tracks in the whole folder hierarchy, excluding cue source images
@@ -464,7 +464,7 @@ public interface Folders { * INTEGER * @since 829 */ - public static final @NonNull String HIER_NUM_FILES = TABLE + ".hier_num_files"; + @NonNull String HIER_NUM_FILES = Folders.TABLE + ".hier_num_files"; /** * Duration in milliseconds for the tracks inside this folder only, excluding cue source images
@@ -472,7 +472,7 @@ public interface Folders { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Folders.TABLE + ".duration"; /** * Duration in milliseconds for the whole hierarchy inside this folder, excluding cue source images
@@ -480,7 +480,7 @@ public interface Folders { * INTEGER * @since 829
*/ - public static final @NonNull String HIER_DURATION = TABLE + ".hier_duration"; + @NonNull String HIER_DURATION = Folders.TABLE + ".hier_duration"; /** * Duration meta
@@ -488,7 +488,7 @@ public interface Folders { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Folders.TABLE + ".dur_meta"; /** * Hierarchy duration meta
@@ -496,42 +496,42 @@ public interface Folders { * TEXT * @since 829
*/ - public static final @NonNull String HIER_DUR_META = TABLE + ".hier_dur_meta"; + @NonNull String HIER_DUR_META = Folders.TABLE + ".hier_dur_meta"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Folders.TABLE + ".aa_status"; /** * If 1 (true), this folder restores last played track
* INTEGER (boolean) * @since 821
*/ - public static final @NonNull String KEEP_LIST_POS = TABLE + ".keep_list_pos"; // Sync with RestLibraryListMemorizable + @NonNull String KEEP_LIST_POS = Folders.TABLE + ".keep_list_pos"; // Sync with RestLibraryListMemorizable /** * If 1 (true), this folder restores last played track position
* INTEGER (boolean) * @since 821
*/ - public static final @NonNull String KEEP_TRACK_POS = TABLE + ".keep_track_pos"; // Sync with RestLibraryListMemorizable + @NonNull String KEEP_TRACK_POS = Folders.TABLE + ".keep_track_pos"; // Sync with RestLibraryListMemorizable - public static final @NonNull String KEEP_LIST_AND_TRACK_POS_COMBINED = "(" + KEEP_TRACK_POS + "<<1)+" + KEEP_LIST_POS; + @NonNull String KEEP_LIST_AND_TRACK_POS_COMBINED = "(" + Folders.KEEP_TRACK_POS + "<<1)+" + Folders.KEEP_LIST_POS; /** * Non-null for provider folders, where provider wants to control default sorting order in Folders Hierarchy
* INTEGER
* @since 869 */ - public static final @NonNull String SORT_ORDER = "sort_order"; + @NonNull String SORT_ORDER = "sort_order"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Folders.TABLE + ".played_at"; // Deprecated @@ -543,7 +543,7 @@ public interface Folders { * @deprecated since 864. {@link #HIER_NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String HIER_NUM_ALL_FILES = TABLE + ".hier_num_all_files"; + @NonNull String HIER_NUM_ALL_FILES = Folders.TABLE + ".hier_num_all_files"; /** * Duration in milliseconds for the tracks inside this folder only, including cue source images
@@ -553,7 +553,7 @@ public interface Folders { * @deprecated since 864. {@link #DURATION} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Folders.TABLE + ".duration_all"; /** * Hierarchy duration meta including cues
@@ -563,7 +563,7 @@ public interface Folders { * @deprecated since 864 */ @Deprecated - public static final @NonNull String HIER_DUR_ALL_META = TABLE + ".hier_dur_all_meta"; + @NonNull String HIER_DUR_ALL_META = Folders.TABLE + ".hier_dur_all_meta"; /** * Duration meta including cues
@@ -573,7 +573,7 @@ public interface Folders { * @deprecated since 864. {@link #DUR_META} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Folders.TABLE + ".dur_all_meta"; /** * Duration in milliseconds for the whole hierarchy inside this folder, including cue source images
@@ -583,7 +583,7 @@ public interface Folders { * @deprecated since 864 */ @Deprecated - public static final @NonNull String HIER_DURATION_ALL = TABLE + ".hier_duration_all"; + @NonNull String HIER_DURATION_ALL = Folders.TABLE + ".hier_duration_all"; /** * Calculated subquery column which retrieves parent name
@@ -591,7 +591,7 @@ public interface Folders { * @deprecated use {@link #PARENT_LABEL} */ @Deprecated - public static final @NonNull String PARENT_NAME_SUBQUERY = "(SELECT name FROM folders AS f2 WHERE f2._id=folders.parent_id) AS parent_name_subquery"; + @NonNull String PARENT_NAME_SUBQUERY = "(SELECT name FROM folders AS f2 WHERE f2._id=folders.parent_id) AS parent_name_subquery"; /** * Calculated subquery column which retrieves short parent name
@@ -599,57 +599,57 @@ public interface Folders { * @deprecated use {@link #PARENT_NAME} */ @Deprecated - public static final @NonNull String PARENT_SHORT_NAME_SUBQUERY = "(SELECT short_name FROM folders AS f2 WHERE f2._id=folders.parent_id) AS parent_short_name_subquery"; + @NonNull String PARENT_SHORT_NAME_SUBQUERY = "(SELECT short_name FROM folders AS f2 WHERE f2._id=folders.parent_id) AS parent_short_name_subquery"; } - public interface Albums { - public static final @NonNull String TABLE = "albums"; + interface Albums { + @NonNull String TABLE = "albums"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Albums.TABLE + "._id"; /** * NOTE: important to have it w/o table for headers-enabled compound selects
* TEXT */ - public static final @NonNull String ALBUM = "album"; + @NonNull String ALBUM = "album"; /** * NOTE: important to have it w/o table for headers-enabled compound selects
* TEXT */ - public static final @NonNull String ALBUM_SORT = "album_sort"; + @NonNull String ALBUM_SORT = "album_sort"; /** * NOTE: this is NULL for Unknown album, so not all joins are possible with just albums + album_artists (use folder_files for joins)
* INTEGER */ - public static final @NonNull String ALBUM_ARTIST_ID = TABLE + ".album_artist_id"; + @NonNull String ALBUM_ARTIST_ID = Albums.TABLE + ".album_artist_id"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Albums.TABLE + ".created_at"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Albums.TABLE + ".num_files"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Albums.TABLE + ".aa_status"; /** * The guessed album year
* INTEGER */ - public static final @NonNull String ALBUM_YEAR = "album_year"; + @NonNull String ALBUM_YEAR = "album_year"; /** * Duration in milliseconds, excluding cue source images
@@ -657,7 +657,7 @@ public interface Albums { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Albums.TABLE + ".duration"; /** * Duration meta
@@ -665,13 +665,13 @@ public interface Albums { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Albums.TABLE + ".dur_meta"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Albums.TABLE + ".played_at"; // Deprecated @@ -682,7 +682,7 @@ public interface Albums { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Albums.TABLE + ".num_all_files"; /** * Duration in milliseconds, including cue source images
@@ -692,7 +692,7 @@ public interface Albums { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Albums.TABLE + ".duration_all"; /** * Duration meta including cues
@@ -702,43 +702,43 @@ public interface Albums { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Albums.TABLE + ".dur_all_meta"; } - public interface Artists { - public static final @NonNull String TABLE = "artists"; + interface Artists { + @NonNull String TABLE = "artists"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Artists.TABLE + "._id"; /** * TEXT */ - public static final @NonNull String ARTIST = "artist"; + @NonNull String ARTIST = "artist"; /** * TEXT */ - public static final @NonNull String ARTIST_SORT = "artist_sort"; + @NonNull String ARTIST_SORT = "artist_sort"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Artists.TABLE + ".created_at"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Artists.TABLE + ".aa_status"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Artists.TABLE + ".num_files"; /** @@ -747,7 +747,7 @@ public interface Artists { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Artists.TABLE + ".duration"; /** * Duration meta
@@ -755,20 +755,20 @@ public interface Artists { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Artists.TABLE + ".dur_meta"; /** * If true (1) this is unsplit combined multi-artist
* INTEGER (boolean) * @since 899
*/ - public static final @NonNull String IS_UNSPLIT = TABLE + ".is_unsplit"; + @NonNull String IS_UNSPLIT = Artists.TABLE + ".is_unsplit"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Artists.TABLE + ".played_at"; // Deprecated @@ -779,7 +779,7 @@ public interface Artists { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Artists.TABLE + ".num_all_files"; /** * Duration in milliseconds, including cue source images
@@ -789,7 +789,7 @@ public interface Artists { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Artists.TABLE + ".duration_all"; /** * Duration meta including cues
@@ -799,7 +799,7 @@ public interface Artists { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Artists.TABLE + ".dur_all_meta"; } /** @@ -807,48 +807,48 @@ public interface Artists { * Always used. First entry may be the UNKNOWN_ID or an unsplit artist * @since 899 */ - public interface MultiArtists { - public static final @NonNull String TABLE = "multi_artists"; + interface MultiArtists { + @NonNull String TABLE = "multi_artists"; - public static final @NonNull String _ID = TABLE + "._id"; - public static final @NonNull String ARTIST_ID = TABLE + ".artist_id"; - public static final @NonNull String FILE_ID = TABLE + ".file_id"; + @NonNull String _ID = MultiArtists.TABLE + "._id"; + @NonNull String ARTIST_ID = MultiArtists.TABLE + ".artist_id"; + @NonNull String FILE_ID = MultiArtists.TABLE + ".file_id"; } /** This is similar to Artists, but uses Album Artist tag, where available */ - public interface AlbumArtists { - public static final @NonNull String TABLE = "album_artists"; + interface AlbumArtists { + @NonNull String TABLE = "album_artists"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = AlbumArtists.TABLE + "._id"; /** * TEXT */ - public static final @NonNull String ALBUM_ARTIST = "album_artist"; + @NonNull String ALBUM_ARTIST = "album_artist"; /** * TEXT */ - public static final @NonNull String ALBUM_ARTIST_SORT = "album_artist_sort"; + @NonNull String ALBUM_ARTIST_SORT = "album_artist_sort"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = AlbumArtists.TABLE + ".created_at"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = AlbumArtists.TABLE + ".aa_status"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = AlbumArtists.TABLE + ".num_files"; /** * Duration in milliseconds, excluding cue source images
@@ -856,7 +856,7 @@ public interface AlbumArtists { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = AlbumArtists.TABLE + ".duration"; /** * Duration meta
@@ -864,20 +864,20 @@ public interface AlbumArtists { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = AlbumArtists.TABLE + ".dur_meta"; /** * If true (1) this is combined unsplit multi-artist
* INTEGER (boolean) * @since 899
*/ - public static final @NonNull String IS_UNSPLIT = TABLE + ".is_unsplit"; + @NonNull String IS_UNSPLIT = AlbumArtists.TABLE + ".is_unsplit"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = AlbumArtists.TABLE + ".played_at"; // Deprecated fields @@ -889,7 +889,7 @@ public interface AlbumArtists { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = AlbumArtists.TABLE + ".dur_all_meta"; /** * Duration in milliseconds, including cue source images
* Dynamically recalculated on rescans
@@ -899,7 +899,7 @@ public interface AlbumArtists { */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = AlbumArtists.TABLE + ".duration_all"; /** * Number of tracks in this category, including cue source images
@@ -908,7 +908,7 @@ public interface AlbumArtists { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = AlbumArtists.TABLE + ".num_all_files"; } /** @@ -916,46 +916,46 @@ public interface AlbumArtists { * Always used. First entry may be the UNKNOWN_ID or an unsplit album artist * @since 899 * */ - public interface MultiAlbumArtists { - public static final @NonNull String TABLE = "multi_album_artists"; + interface MultiAlbumArtists { + @NonNull String TABLE = "multi_album_artists"; - public static final @NonNull String _ID = TABLE + "._id"; - public static final @NonNull String ALBUM_ARTIST_ID = TABLE + ".album_artist_id"; - public static final @NonNull String FILE_ID = TABLE + ".file_id"; + @NonNull String _ID = MultiAlbumArtists.TABLE + "._id"; + @NonNull String ALBUM_ARTIST_ID = MultiAlbumArtists.TABLE + ".album_artist_id"; + @NonNull String FILE_ID = MultiAlbumArtists.TABLE + ".file_id"; } /** * Album => artist 1:1 binding table
* Used for Albums by Artist category, where can be multiple same Album repeated per each Artist */ - public interface AlbumsByArtist { - public static final @NonNull String TABLE = "artist_albums"; + interface AlbumsByArtist { + @NonNull String TABLE = "artist_albums"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = AlbumsByArtist.TABLE + "._id"; /** * INTEGER */ - public static final @NonNull String ARTIST_ID = TABLE + ".artist_id"; + @NonNull String ARTIST_ID = AlbumsByArtist.TABLE + ".artist_id"; /** * INTEGER */ - public static final @NonNull String ALBUM_ID = TABLE + ".album_id"; + @NonNull String ALBUM_ID = AlbumsByArtist.TABLE + ".album_id"; /** * First seen time
* Seconds unix time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = AlbumsByArtist.TABLE + ".created_at"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = AlbumsByArtist.TABLE + ".num_files"; /** * Duration in milliseconds, excluding cue source images
@@ -963,13 +963,13 @@ public interface AlbumsByArtist { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = AlbumsByArtist.TABLE + ".duration"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = AlbumsByArtist.TABLE + ".played_at"; // Deprecated @@ -980,7 +980,7 @@ public interface AlbumsByArtist { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = AlbumsByArtist.TABLE + ".num_all_files"; /** * Duration in milliseconds, including cue source images
@@ -990,7 +990,7 @@ public interface AlbumsByArtist { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = AlbumsByArtist.TABLE + ".duration_all"; /** * Duration meta
@@ -998,7 +998,7 @@ public interface AlbumsByArtist { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = AlbumsByArtist.TABLE + ".dur_meta"; /** * Duration meta including cues
@@ -1008,43 +1008,43 @@ public interface AlbumsByArtist { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = AlbumsByArtist.TABLE + ".dur_all_meta"; } - public interface Composers { - public static final @NonNull String TABLE = "composers"; + interface Composers { + @NonNull String TABLE = "composers"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Composers.TABLE + "._id"; /** * TEXT */ - public static final @NonNull String COMPOSER = "composer"; + @NonNull String COMPOSER = "composer"; /** * INTEGER */ - public static final @NonNull String COMPOSER_SORT = "composer_sort"; + @NonNull String COMPOSER_SORT = "composer_sort"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Composers.TABLE + ".created_at"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Composers.TABLE + ".aa_status"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Composers.TABLE + ".num_files"; /** * Duration in milliseconds, excluding cue source images
@@ -1052,7 +1052,7 @@ public interface Composers { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Composers.TABLE + ".duration"; /** * Duration meta
@@ -1060,20 +1060,20 @@ public interface Composers { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Composers.TABLE + ".dur_meta"; /** * If true (1) this is combined unsplit multi-composer
* INTEGER (boolean) * @since 899
*/ - public static final @NonNull String IS_UNSPLIT = TABLE + ".is_unsplit"; + @NonNull String IS_UNSPLIT = Composers.TABLE + ".is_unsplit"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Composers.TABLE + ".played_at"; // Deprecated @@ -1084,7 +1084,7 @@ public interface Composers { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Composers.TABLE + ".num_all_files"; /** * Duration in milliseconds, including cue source images
@@ -1094,7 +1094,7 @@ public interface Composers { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Composers.TABLE + ".duration_all"; /** * Duration meta including cues
@@ -1104,7 +1104,7 @@ public interface Composers { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Composers.TABLE + ".dur_all_meta"; } @@ -1113,37 +1113,37 @@ public interface Composers { * Always used. First entry may be the UNKNOWN_ID or an unsplit composer * @since 899 * */ - public interface MultiComposers { - public static final @NonNull String TABLE = "multi_composers"; + interface MultiComposers { + @NonNull String TABLE = "multi_composers"; - public static final @NonNull String _ID = TABLE + "._id"; - public static final @NonNull String COMPOSER_ID = TABLE + ".composer_id"; - public static final @NonNull String FILE_ID = TABLE + ".file_id"; + @NonNull String _ID = MultiComposers.TABLE + "._id"; + @NonNull String COMPOSER_ID = MultiComposers.TABLE + ".composer_id"; + @NonNull String FILE_ID = MultiComposers.TABLE + ".file_id"; } - public interface Genres { - public static final @NonNull String TABLE = "genres"; + interface Genres { + @NonNull String TABLE = "genres"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Genres.TABLE + "._id"; /** * TEXT */ - public static final @NonNull String GENRE = "genre"; + @NonNull String GENRE = "genre"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Genres.TABLE + ".created_at"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Genres.TABLE + ".num_files"; /** * Duration in milliseconds, excluding cue source images
@@ -1151,7 +1151,7 @@ public interface Genres { * INTEGER * @since 829
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Genres.TABLE + ".duration"; /** * Duration meta
@@ -1159,19 +1159,19 @@ public interface Genres { * TEXT * @since 829
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Genres.TABLE + ".dur_meta"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Genres.TABLE + ".aa_status"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Genres.TABLE + ".played_at"; // Deprecated @@ -1182,7 +1182,7 @@ public interface Genres { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Genres.TABLE + ".num_all_files"; /** * Duration meta including cues
@@ -1192,7 +1192,7 @@ public interface Genres { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Genres.TABLE + ".dur_all_meta"; /** * Duration in milliseconds, including cue source images
@@ -1202,81 +1202,81 @@ public interface Genres { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Genres.TABLE + ".duration_all"; } - public interface GenreEntries { - public static final @NonNull String TABLE = "genre_entries"; + interface GenreEntries { + @NonNull String TABLE = "genre_entries"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = GenreEntries.TABLE + "._id"; /** * Actual id of the file in folder_files table
* INTEGER */ - public static final @NonNull String FOLDER_FILE_ID = "folder_file_id"; + @NonNull String FOLDER_FILE_ID = "folder_file_id"; /** * Genre id
* INTEGER */ - public static final @NonNull String GENRE_ID = "genre_id"; + @NonNull String GENRE_ID = "genre_id"; } /** * @since 856 */ - public interface Years { - public static final @NonNull String TABLE = "years"; + interface Years { + @NonNull String TABLE = "years"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Years.TABLE + "._id"; /** * INTEGER */ - public static final @NonNull String YEAR = TABLE + ".year"; + @NonNull String YEAR = Years.TABLE + ".year"; /** * First seen time
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Years.TABLE + ".created_at"; /** * Number of tracks in this category, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Years.TABLE + ".num_files"; /** * Duration in milliseconds, excluding cue source images
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Years.TABLE + ".duration"; /** * Duration meta
* Dynamically recalculated on rescans
* TEXT */ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Years.TABLE + ".dur_meta"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Years.TABLE + ".aa_status"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Years.TABLE + ".played_at"; // Deprecated @@ -1287,7 +1287,7 @@ public interface Years { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DUR_ALL_META = TABLE + ".dur_all_meta"; + @NonNull String DUR_ALL_META = Years.TABLE + ".dur_all_meta"; /** * Duration in milliseconds, including cue source images
@@ -1296,7 +1296,7 @@ public interface Years { * @deprecated since 864 */ @Deprecated - public static final @NonNull String DURATION_ALL = TABLE + ".duration_all"; + @NonNull String DURATION_ALL = Years.TABLE + ".duration_all"; /** * Number of tracks in this category, including cue source images
@@ -1305,7 +1305,7 @@ public interface Years { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Years.TABLE + ".num_all_files"; } @@ -1314,166 +1314,166 @@ public interface Years { * TYPE + REF_ID is an unique index * @since 863 */ - public interface CatStats { - public static final @NonNull String TABLE = "cat_stats"; + interface CatStats { + @NonNull String TABLE = "cat_stats"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = CatStats.TABLE + "._id"; /** * Matches category numeric type ({@link PowerampAPI.Cats})
* INTEGER */ - public static final @NonNull String TYPE = TABLE + ".type"; + @NonNull String TYPE = CatStats.TABLE + ".type"; /** * First referenced target id, e.g. genre _id
* INTEGER */ - public static final @NonNull String REF_ID = TABLE + ".ref_id"; + @NonNull String REF_ID = CatStats.TABLE + ".ref_id"; /** * Second referenced target id, e.g. album _id
* INTEGER */ - public static final @NonNull String REF_ID2 = TABLE + ".ref_id2"; + @NonNull String REF_ID2 = CatStats.TABLE + ".ref_id2"; /** * Number of tracks in this category
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = CatStats.TABLE + ".num_files"; /** * Duration in milliseconds
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = CatStats.TABLE + ".duration"; /** * Duration meta
* Dynamically recalculated on rescans
* TEXT */ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = CatStats.TABLE + ".dur_meta"; } - public interface PlaylistEntries { - public static final @NonNull String TABLE = "playlist_entries"; + interface PlaylistEntries { + @NonNull String TABLE = "playlist_entries"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = PlaylistEntries.TABLE + "._id"; /** * Actual id of the file in folder_files table
* INTEGER */ - public static final @NonNull String FOLDER_FILE_ID = "folder_file_id"; + @NonNull String FOLDER_FILE_ID = "folder_file_id"; /** * Folder Playlist id
* INTEGER */ - public static final @NonNull String PLAYLIST_ID = "playlist_id"; + @NonNull String PLAYLIST_ID = "playlist_id"; /** * Sort order
* INTEGER */ - public static final @NonNull String SORT = "sort"; + @NonNull String SORT = "sort"; /** * Filename, the full or final part of the stream URL
* TEXT * @since 842
*/ - public static final @NonNull String FILE_NAME = "file_name"; + @NonNull String FILE_NAME = "file_name"; /** * Parent folder path (matching {@link Folders#PATH}, or base URL (or NULL) for streams
* TEXT * @since 842
*/ - public static final @NonNull String FOLDER_PATH = "folder_path"; + @NonNull String FOLDER_PATH = "folder_path"; /** * Cue offset for .cue tracks
* INTEGER * @since 842
*/ - public static final @NonNull String CUE_OFFSET_MS = TABLE + ".cue_offset_ms"; + @NonNull String CUE_OFFSET_MS = PlaylistEntries.TABLE + ".cue_offset_ms"; /** * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = PlaylistEntries.TABLE + ".played_at"; /** * INTEGER */ - public static final @NonNull String SHUFFLE_ORDER = TABLE + ".shuffle_order"; + @NonNull String SHUFFLE_ORDER = PlaylistEntries.TABLE + ".shuffle_order"; } - public interface Playlists { - public static final @NonNull String TABLE = "playlists"; + interface Playlists { + @NonNull String TABLE = "playlists"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = Playlists.TABLE + "._id"; /** * Name of the playlist
* TEXT */ - public static final @NonNull String PLAYLIST = TABLE + ".playlist"; + @NonNull String PLAYLIST = Playlists.TABLE + ".playlist"; /** * Updated to match file based playlist. Also updated on entry insert/reorder/deletion - for all playlists
* INTEGER */ - public static final @NonNull String MTIME = TABLE + ".mtime"; + @NonNull String MTIME = Playlists.TABLE + ".mtime"; /** * TEXT */ - public static final @NonNull String PATH = TABLE + ".playlist_path"; + @NonNull String PATH = Playlists.TABLE + ".playlist_path"; /** * Seconds
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = Playlists.TABLE + ".created_at"; /** * Seconds
* INTEGER */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + @NonNull String UPDATED_AT = Playlists.TABLE + ".updated_at"; /** * Number of playlist entries
* Dynamically recalculated on rescans
* INTEGER */ - public static final @NonNull String NUM_FILES = TABLE + ".num_files"; + @NonNull String NUM_FILES = Playlists.TABLE + ".num_files"; /** * Bitwise flag
* INTEGER */ - public static final @NonNull String AA_STATUS = TABLE + ".aa_status"; + @NonNull String AA_STATUS = Playlists.TABLE + ".aa_status"; /** * INTEGER (boolean) */ - public static final @NonNull String KEEP_LIST_POS = TABLE + ".keep_list_pos"; // Sync with RestLibraryListMemorizable + @NonNull String KEEP_LIST_POS = Playlists.TABLE + ".keep_list_pos"; // Sync with RestLibraryListMemorizable /** * INTEGER (boolean) */ - public static final @NonNull String KEEP_TRACK_POS = TABLE + ".keep_track_pos"; // Sync with RestLibraryListMemorizable + @NonNull String KEEP_TRACK_POS = Playlists.TABLE + ".keep_track_pos"; // Sync with RestLibraryListMemorizable - public static final @NonNull String KEEP_LIST_AND_TRACK_POS_COMBINED = "(" + KEEP_TRACK_POS + "<<1)+" + KEEP_LIST_POS; + @NonNull String KEEP_LIST_AND_TRACK_POS_COMBINED = "(" + Playlists.KEEP_TRACK_POS + "<<1)+" + Playlists.KEEP_LIST_POS; /** * Duration in milliseconds
@@ -1481,7 +1481,7 @@ public interface Playlists { * INTEGER * @since 826
*/ - public static final @NonNull String DURATION = TABLE + ".duration"; + @NonNull String DURATION = Playlists.TABLE + ".duration"; /** * Duration meta
@@ -1489,19 +1489,19 @@ public interface Playlists { * TEXT * @since 826
*/ - public static final @NonNull String DUR_META = TABLE + ".dur_meta"; + @NonNull String DUR_META = Playlists.TABLE + ".dur_meta"; /** * Calculated column * INTEGER (boolean) */ - public static final @NonNull String IS_FILE = TABLE + ".playlist_path IS NOT NULL AS _is_file"; + @NonNull String IS_FILE = Playlists.TABLE + ".playlist_path IS NOT NULL AS _is_file"; /** * This is usually not updated, unless shuffled * INTEGER */ - public static final @NonNull String PLAYED_AT = TABLE + ".played_at"; + @NonNull String PLAYED_AT = Playlists.TABLE + ".played_at"; // Deprecated @@ -1515,37 +1515,38 @@ public interface Playlists { * @deprecated since 864. {@link #NUM_FILES} is now dynamically updated depending on "show cue images" preference */ @Deprecated - public static final @NonNull String NUM_ALL_FILES = TABLE + ".num_all_files"; + @NonNull String NUM_ALL_FILES = Playlists.TABLE + ".num_all_files"; } - public class Queue { - public static final @NonNull String TABLE = "queue"; + enum Queue { + ; + public static final @NonNull String TABLE = "queue"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = Queue.TABLE + "._id"; /** * Folder file id
* INTEGER */ - public static final @NonNull String FOLDER_FILE_ID = TABLE + ".folder_file_id"; + public static final @NonNull String FOLDER_FILE_ID = Queue.TABLE + ".folder_file_id"; /** * Milliseconds
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + public static final @NonNull String CREATED_AT = Queue.TABLE + ".created_at"; /** * INTEGER */ - public static final @NonNull String SORT = TABLE + ".sort"; + public static final @NonNull String SORT = Queue.TABLE + ".sort"; /** * INTEGER */ - public static final @NonNull String SHUFFLE_ORDER = TABLE + ".shuffle_order"; + public static final @NonNull String SHUFFLE_ORDER = Queue.TABLE + ".shuffle_order"; public static final @NonNull String CALC_PLAYED = "folder_files.played_at >= queue.created_at"; // If played at is the same as queue entry time, consider it played already public static final @NonNull String CALC_UNPLAYED = "folder_files.played_at < queue.created_at"; @@ -1554,53 +1555,56 @@ public class Queue { /** * @since 877 */ - public class Bookmarks { - public static final @NonNull String TABLE = "bookmarks"; + enum Bookmarks { + ; + public static final @NonNull String TABLE = "bookmarks"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = Bookmarks.TABLE + "._id"; /** * Folder file id
* INTEGER */ - public static final @NonNull String FOLDER_FILE_ID = TABLE + ".folder_file_id"; + public static final @NonNull String FOLDER_FILE_ID = Bookmarks.TABLE + ".folder_file_id"; /** * Milliseconds
* INTEGER */ - public static final @NonNull String OFFSET_MS = TABLE + ".offset_ms"; + public static final @NonNull String OFFSET_MS = Bookmarks.TABLE + ".offset_ms"; /** * INTEGER */ - public static final @NonNull String SORT = TABLE + ".sort"; + public static final @NonNull String SORT = Bookmarks.TABLE + ".sort"; /** * TEXT */ - public static final @NonNull String META = TABLE + ".meta"; + public static final @NonNull String META = Bookmarks.TABLE + ".meta"; /** * Milliseconds
* INTEGER */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + public static final @NonNull String CREATED_AT = Bookmarks.TABLE + ".created_at"; } /** Never used, to be removed */ @Deprecated - public class ShuffleSessionIds { - public static final @NonNull String TABLE = "shuffle_session_ids"; + enum ShuffleSessionIds { + ; + public static final @NonNull String TABLE = "shuffle_session_ids"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = ShuffleSessionIds.TABLE + "._id"; } - public class EqPresets { - public static final @NonNull String TABLE = "eq_presets"; + enum EqPresets { + ; + public static final @NonNull String TABLE = "eq_presets"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = EqPresets.TABLE + "._id"; /** * If non-null - this is the predefined preset (see res/values/arrays/eq_preset_labels).
@@ -1615,7 +1619,7 @@ public class EqPresets { * The text version of data is supported for the graphic mode only (since 906) * TEXT */ - public static final @NonNull String _DATA = TABLE + "._data"; + public static final @NonNull String _DATA = EqPresets.TABLE + "._data"; /** * Eq preset data. Either this or _data is used for the preset data, app always saves to DATA_BLOB.
@@ -1625,21 +1629,21 @@ public class EqPresets { * BLOB * @since 906 */ - public static final @NonNull String DATA_BLOB = TABLE + ".data_blob"; + public static final @NonNull String DATA_BLOB = EqPresets.TABLE + ".data_blob"; /** * Default eq preset data for built-in and AutoEq presets. * BLOB * @since 960 */ - public static final @NonNull String DEFAULT_BLOB = TABLE + ".default_blob"; + public static final @NonNull String DEFAULT_BLOB = EqPresets.TABLE + ".default_blob"; /** * Eq preset data resolved to either user changed data (if any) or the default preset data
* BLOB * @since 960 */ - public static final @NonNull String RESOLVED_BLOB = "COALESCE(" + DATA_BLOB + "," + DEFAULT_BLOB + ")"; + public static final @NonNull String RESOLVED_BLOB = "COALESCE(" + EqPresets.DATA_BLOB + "," + EqPresets.DEFAULT_BLOB + ")"; /** * 1 if preset is parametric
@@ -1652,13 +1656,13 @@ public class EqPresets { * Preset name
* TEXT */ - public static final @NonNull String NAME = TABLE + ".name"; + public static final @NonNull String NAME = EqPresets.TABLE + ".name"; /** * Additional meta information, such as AutoEq category
* TEXT */ - public static final @NonNull String META = TABLE + ".meta"; + public static final @NonNull String META = EqPresets.TABLE + ".meta"; /** * Updated automatically when name, _data, data_blob, or parametric fields are updated, other fields ignored
@@ -1666,7 +1670,7 @@ public class EqPresets { * INTEGER * @since 906 */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + public static final @NonNull String UPDATED_AT = EqPresets.TABLE + ".updated_at"; /** * BLOB @@ -1688,7 +1692,7 @@ public class EqPresets { * @see EqPresetConsts * @since 960 */ - public static final @NonNull String TYPE = TABLE + ".type"; + public static final @NonNull String TYPE = EqPresets.TABLE + ".type"; /** * 1 if preset is bound to speaker, 0 otherwise
@@ -1876,37 +1880,39 @@ public class EqPresets { * @deprecated not used since 962 */ @Deprecated - public static final @NonNull String SORT = TABLE + ".sort"; + public static final @NonNull String SORT = EqPresets.TABLE + ".sort"; } - public static final class EqPresetSongs { - public static final @NonNull String TABLE = "eq_preset_songs"; + enum EqPresetSongs { + ; + public static final @NonNull String TABLE = "eq_preset_songs"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = EqPresetSongs.TABLE + "._id"; /** * Either folder_file_id
* INTEGER */ - public static final @NonNull String FILE_ID = TABLE + ".file_id"; + public static final @NonNull String FILE_ID = EqPresetSongs.TABLE + ".file_id"; /** * Eq preset id
* INTEGER */ - public static final @NonNull String PRESET_ID = TABLE + ".preset_id"; + public static final @NonNull String PRESET_ID = EqPresetSongs.TABLE + ".preset_id"; } - public static final class EqPresetDevices { - public static final @NonNull String TABLE = "eq_preset_devices"; + enum EqPresetDevices { + ; + public static final @NonNull String TABLE = "eq_preset_devices"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = EqPresetDevices.TABLE + "._id"; /** * Eq preset id
* INTEGER */ - public static final @NonNull String PRESET_ID = TABLE + ".preset_id"; + public static final @NonNull String PRESET_ID = EqPresetDevices.TABLE + ".preset_id"; /** * Device type
@@ -1928,39 +1934,42 @@ public static final class EqPresetDevices { } /** @since 960 */ - public static final class KnownDevices { - public static final @NonNull String TABLE = "known_devices"; + enum KnownDevices { + ; + public static final @NonNull String TABLE = "known_devices"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = KnownDevices.TABLE + "._id"; /** * Device name
* TEXT */ - public static final @NonNull String DEVICE_NAME = TABLE + ".device_name"; + public static final @NonNull String DEVICE_NAME = KnownDevices.TABLE + ".device_name"; } - public class ReverbPresets { - public static final @NonNull String TABLE = "reverb_presets"; + enum ReverbPresets { + ; + public static final @NonNull String TABLE = "reverb_presets"; - public static final @NonNull String _ID = TABLE + "._id"; + public static final @NonNull String _ID = ReverbPresets.TABLE + "._id"; /** * TEXT */ - public static final @NonNull String _DATA = TABLE + "._data"; + public static final @NonNull String _DATA = ReverbPresets.TABLE + "._data"; /** * TEXT */ - public static final @NonNull String NAME = TABLE + ".name"; + public static final @NonNull String NAME = ReverbPresets.TABLE + ".name"; } /** @since 841 */ - public class PrefSearch { - public static final @NonNull String TABLE = "pref_search"; - public static final @NonNull String _ID = TABLE + "._id"; + enum PrefSearch { + ; + public static final @NonNull String TABLE = "pref_search"; + public static final @NonNull String _ID = PrefSearch.TABLE + "._id"; public static final @NonNull String BREADCRUMB = "breadcrumb"; public static final @NonNull String PREF_URI = "pref_uri"; public static final @NonNull String PREF_KEY = "pref_key"; @@ -1969,8 +1978,9 @@ public class PrefSearch { } /** @since 841 */ - public class PrefSearchFts { - public static final @NonNull String TABLE = "pref_search_fts"; + enum PrefSearchFts { + ; + public static final @NonNull String TABLE = "pref_search_fts"; public static final @NonNull String DOCID = "docid"; public static final @NonNull String TITLE = "title"; public static final @NonNull String SUMMARY = "summary"; @@ -1980,102 +1990,103 @@ public class PrefSearchFts { * Search history for the main (tracks) search * @since 907 */ - public class SearchHistory { - public static final @NonNull String TABLE = "search_history"; - public static final @NonNull String _ID = TABLE + "._id"; + enum SearchHistory { + ; + public static final @NonNull String TABLE = "search_history"; + public static final @NonNull String _ID = SearchHistory.TABLE + "._id"; public static final @NonNull String TERM = "term"; - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + public static final @NonNull String UPDATED_AT = SearchHistory.TABLE + ".updated_at"; } /** * LRC files found during the file system/providers scan * @since 948 */ - public interface LrcFiles { - public static final @NonNull String TABLE = "lrc_files"; + interface LrcFiles { + @NonNull String TABLE = "lrc_files"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = LrcFiles.TABLE + "._id"; /** * First seen time
* Seconds
* INTEGER NOT NULL */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = LrcFiles.TABLE + ".created_at"; /** * Time of update
* Seconds
* INTEGER NOT NULL */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + @NonNull String UPDATED_AT = LrcFiles.TABLE + ".updated_at"; /** * LRC file mtime
* INTEGER NOT NULL */ - public static final @NonNull String MTIME = TABLE + ".mtime"; + @NonNull String MTIME = LrcFiles.TABLE + ".mtime"; /** * Title extracted either from [ti:] tag or from the file name or NULL if none
* TEXT NULL */ - public static final @NonNull String TITLE = TABLE + ".title"; + @NonNull String TITLE = LrcFiles.TABLE + ".title"; /** * Artist extracted either from [ar:] tag or from the file name or NULL if none
* TEXT NULL */ - public static final @NonNull String ARTIST = TABLE + ".artist"; + @NonNull String ARTIST = LrcFiles.TABLE + ".artist"; /** * [al:] album tag contents or NULL if none
* TEXT NULL */ - public static final @NonNull String ALBUM = TABLE + ".album"; + @NonNull String ALBUM = LrcFiles.TABLE + ".album"; /** * [length:] tag in milliseconds or NULL if none or 0
* INTEGER NULL */ - public static final @NonNull String LENGTH = TABLE + ".length"; + @NonNull String LENGTH = LrcFiles.TABLE + ".length"; /** * Simple filename - the filename without path or extension
* TEXT NON NULL */ - public static final @NonNull String SIMPLE_FILENAME = TABLE + ".simple_filename"; + @NonNull String SIMPLE_FILENAME = LrcFiles.TABLE + ".simple_filename"; /** * File extension with the dot, e.g. ".lrc" or empty string if none
* TEXT NON NULL */ - public static final @NonNull String EXTENSION = TABLE + ".extension"; + @NonNull String EXTENSION = LrcFiles.TABLE + ".extension"; /** * Parent folder path including the last /
* TEXT NON NULL */ - public static final @NonNull String FOLDER_PATH = TABLE + ".folder_path"; + @NonNull String FOLDER_PATH = LrcFiles.TABLE + ".folder_path"; /** * 1 if this file should be treated as utf8
* BOOLEAN NON NULL */ - public static final @NonNull String IS_UTF8 = TABLE + ".is_utf8"; + @NonNull String IS_UTF8 = LrcFiles.TABLE + ".is_utf8"; /** * One of the TAG_* constants
* INTEGER NOT NULL * @see com.maxmpz.poweramp.player.PowerampAPI.Track.TagStatus */ - public static final @NonNull String TAG_STATUS = TABLE + ".tag_status"; + @NonNull String TAG_STATUS = LrcFiles.TABLE + ".tag_status"; /** * Full path to the lrc file.
* Calculated field */ - public static final @NonNull String FULL_PATH = FOLDER_PATH + "||" + SIMPLE_FILENAME + "||" + EXTENSION; + @NonNull String FULL_PATH = LrcFiles.FOLDER_PATH + "||" + LrcFiles.SIMPLE_FILENAME + "||" + LrcFiles.EXTENSION; } /** @@ -2083,44 +2094,44 @@ public interface LrcFiles { * LRC files and embedded/tag lyrics are always loaded from the respective LRC file or the track tag. * @since 948 */ - public interface CachedLyrics { - public static final @NonNull String TABLE = "cached_lyrics"; + interface CachedLyrics { + @NonNull String TABLE = "cached_lyrics"; - public static final @NonNull String _ID = TABLE + "._id"; + @NonNull String _ID = CachedLyrics.TABLE + "._id"; /** * First seen time
* Seconds
* INTEGER NOT NULL */ - public static final @NonNull String CREATED_AT = TABLE + ".created_at"; + @NonNull String CREATED_AT = CachedLyrics.TABLE + ".created_at"; /** * Time of update
* Seconds
* INTEGER NOT NULL */ - public static final @NonNull String UPDATED_AT = TABLE + ".updated_at"; + @NonNull String UPDATED_AT = CachedLyrics.TABLE + ".updated_at"; /** * 3rd party plugin package, the source of the lyrics * TEXT NULL */ - public static final @NonNull String CREATED_BY_PAK = TABLE + ".created_by_pak"; + @NonNull String CREATED_BY_PAK = CachedLyrics.TABLE + ".created_by_pak"; /** * 3rd party plugin info line text, shown as last line in Poweramp lyrics. Can be copyright or other similar * additional short info text * TEXT NULL */ - public static final @NonNull String INFO_LINE = TABLE + ".info_line"; + @NonNull String INFO_LINE = CachedLyrics.TABLE + ".info_line"; /** * Lyrics content or NULL if none.
* NOTE: we may have NULL while lyrics is requested via the plugin, but we haven't received data from it yet * TEXT */ - public static final @NonNull String CONTENT = TABLE + ".content"; + @NonNull String CONTENT = CachedLyrics.TABLE + ".content"; } } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderConsts.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderConsts.java index 82676c4d..ee3f1225 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderConsts.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderConsts.java @@ -22,8 +22,9 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING /** * Constants used for Poweramp Track Provider API */ -public class TrackProviderConsts { - /** +public enum TrackProviderConsts { + ; + /** * Column for optional album artist tag.
* String */ diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderHelper.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderHelper.java index c33497bf..3e79bb5c 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderHelper.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderHelper.java @@ -28,20 +28,20 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING /** * Some useful track provider related helper methods */ -public class TrackProviderHelper { - private static final String TAG = "TrackProviderHelper"; +public enum TrackProviderHelper { + ; + private static final String TAG = "TrackProviderHelper"; private static final boolean LOG = false; /** Converts bytes to float array */ - public static float @NonNull[] bytesToFloats(byte @NonNull[] waveBytes) { - if(waveBytes.length == 0) { + public static float @NonNull[] bytesToFloats(final byte @NonNull[] waveBytes) { + if(0 == waveBytes.length) { return new float[0]; } - @SuppressLint("InlinedApi") - int floatSize = waveBytes.length / Float.BYTES; + @SuppressLint("InlinedApi") final int floatSize = waveBytes.length / Float.BYTES; - float[] wave = new float[floatSize]; // Alloc - ByteBuffer bb = ByteBuffer.wrap(waveBytes); // Allocs + final float[] wave = new float[floatSize]; // Alloc + final ByteBuffer bb = ByteBuffer.wrap(waveBytes); // Allocs bb.asFloatBuffer().get(wave); // Alloc return wave; @@ -49,13 +49,12 @@ public class TrackProviderHelper { /** Converts float array to bytes */ @SuppressWarnings("null") - public static byte @NonNull[] floatsToBytes(float @NonNull[] wave) { - if(wave.length == 0) { + public static byte @NonNull[] floatsToBytes(final float @NonNull[] wave) { + if(0 == wave.length) { return new byte[0]; } - @SuppressLint("InlinedApi") - ByteBuffer bb = ByteBuffer.allocate(wave.length * Float.BYTES); - FloatBuffer fb = bb.asFloatBuffer(); // Allocs + @SuppressLint("InlinedApi") final ByteBuffer bb = ByteBuffer.allocate(wave.length * Float.BYTES); + final FloatBuffer fb = bb.asFloatBuffer(); // Allocs fb.put(wave); return bb.array(); } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderProto.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderProto.java index 7c96ed7f..b3eaf35f 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderProto.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/player/TrackProviderProto.java @@ -61,10 +61,10 @@ public class TrackProviderProto implements AutoCloseable { private static final int MAX_PACKET_HEADER_SIZE = 12; /** Header(12) + fileLength(8) + size(4) + */ - private static final int INITIAL_PACKET_SIZE = MAX_PACKET_HEADER_SIZE + 8 + 4; + private static final int INITIAL_PACKET_SIZE = TrackProviderProto.MAX_PACKET_HEADER_SIZE + 8 + 4; /** Index of the first data byte in the packet */ - private static final int PACKET_DATA_IX = MAX_PACKET_HEADER_SIZE; + private static final int PACKET_DATA_IX = TrackProviderProto.MAX_PACKET_HEADER_SIZE; /** Index of the data size (short) */ private static final int PACKET_DATA_SIZE_IX = 6; @@ -88,7 +88,7 @@ public class TrackProviderProto implements AutoCloseable { /** Buffer for header + some extra space for few small packet types */ private final @NonNull ByteBuffer mHeaderBuffer; private final long mFileLength; - private int mState = STATE_INITIAL; + private int mState = TrackProviderProto.STATE_INITIAL; private final StructPollfd @NonNull[] mStructPollFds; private final @NonNull SeekRequest mTempSeekRequest = new SeekRequest(); @@ -96,11 +96,11 @@ public class TrackProviderProto implements AutoCloseable { /** Raised if we failed with the connection/action and can't continue anymore */ @SuppressWarnings("serial") public static class TrackProviderProtoException extends RuntimeException { - public TrackProviderProtoException(Throwable ex) { + public TrackProviderProtoException(final Throwable ex) { super(ex); } - public TrackProviderProtoException(String msg) { + public TrackProviderProtoException(final String msg) { super(msg); } } @@ -108,7 +108,7 @@ public TrackProviderProtoException(String msg) { /** Raised when connection is closed by Poweramp */ @SuppressWarnings("serial") public static class TrackProviderProtoClosed extends RuntimeException { - public TrackProviderProtoClosed(Throwable ex) { + public TrackProviderProtoClosed(final Throwable ex) { super(ex); } } @@ -128,7 +128,7 @@ public static class SeekRequest { @Override public String toString() { - return super.toString() + " offsetBytes=" + offsetBytes + " ms=" + ms; + return super.toString() + " offsetBytes=" + this.offsetBytes + " ms=" + this.ms; } } @@ -138,56 +138,56 @@ public String toString() { * @param fileLength the actual total length of the track being played */ @SuppressLint("NewApi") - public TrackProviderProto(@NonNull ParcelFileDescriptor pfd, long fileLength) { - if(fileLength <= 0) throw new IllegalArgumentException("bad fileLength=" + fileLength); - FileDescriptor socket = pfd.getFileDescriptor(); + public TrackProviderProto(@NonNull final ParcelFileDescriptor pfd, final long fileLength) { + if(0 >= fileLength) throw new IllegalArgumentException("bad fileLength=" + fileLength); + final FileDescriptor socket = pfd.getFileDescriptor(); try { - if(socket == null || !OsConstants.S_ISSOCK(Os.fstat(socket).st_mode)) throw new IllegalArgumentException("bad pfd=" + pfd); - } catch(ErrnoException ex) { + if(null == socket || !OsConstants.S_ISSOCK(Os.fstat(socket).st_mode)) throw new IllegalArgumentException("bad pfd=" + pfd); + } catch(final ErrnoException ex) { throw new TrackProviderProtoException(ex); } - mSocket = socket; - mFileLength = fileLength; + this.mSocket = socket; + this.mFileLength = fileLength; - ByteBuffer headerBuffer = ByteBuffer.allocateDirect(INITIAL_PACKET_SIZE); - if(headerBuffer == null) throw new TrackProviderProtoException("headerBuffer"); - mHeaderBuffer = headerBuffer; - mHeaderBuffer.order(ByteOrder.nativeOrder()); + final ByteBuffer headerBuffer = ByteBuffer.allocateDirect(TrackProviderProto.INITIAL_PACKET_SIZE); + if(null == headerBuffer) throw new TrackProviderProtoException("headerBuffer"); + this.mHeaderBuffer = headerBuffer; + this.mHeaderBuffer.order(ByteOrder.nativeOrder()); - mStructPollFds = new StructPollfd[] { + this.mStructPollFds = new StructPollfd[] { new StructPollfd() }; - mStructPollFds[0].fd = mSocket; - mStructPollFds[0].events = (short)OsConstants.POLLIN; + this.mStructPollFds[0].fd = this.mSocket; + this.mStructPollFds[0].events = (short)OsConstants.POLLIN; } @Override public void close() { - if(LOG) Log.w(TAG, "close"); - if(DEBUG_CHECKS && mState == STATE_CLOSED) throw new AssertionError(); - if(mState != STATE_CLOSED) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "close"); + if(TrackProviderProto.DEBUG_CHECKS && STATE_CLOSED == mState) throw new AssertionError(); + if(STATE_CLOSED != mState) { try { - Os.shutdown(mSocket, 0); - } catch(ErrnoException ex) { - Log.e(TAG, "", ex); + Os.shutdown(this.mSocket, 0); + } catch(final ErrnoException ex) { + Log.e(TrackProviderProto.TAG, "", ex); } try { - Os.close(mSocket); - } catch(ErrnoException ex) { - Log.e(TAG, "", ex); + Os.close(this.mSocket); + } catch(final ErrnoException ex) { + Log.e(TrackProviderProto.TAG, "", ex); } - mState = STATE_CLOSED; - if(LOG) Log.w(TAG, "close OK"); + this.mState = TrackProviderProto.STATE_CLOSED; + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "close OK"); } } /** Prepares packet header buffer */ - private @NonNull ByteBuffer preparePacketHeader(short packetType, int dataSize) { - ByteBuffer buf = mHeaderBuffer; + private @NonNull ByteBuffer preparePacketHeader(final short packetType, final int dataSize) { + final ByteBuffer buf = this.mHeaderBuffer; buf.clear(); - buf.putInt(PACKET_TAG); + buf.putInt(TrackProviderProto.PACKET_TAG); buf.putShort(packetType); - if(DEBUG_CHECKS && dataSize < 0 || dataSize > MAX_DATA_SIZE) throw new AssertionError(dataSize); + if(TrackProviderProto.DEBUG_CHECKS && 0 > dataSize || MAX_DATA_SIZE < dataSize) throw new AssertionError(dataSize); buf.putShort((short)dataSize); buf.putInt(0); return buf; @@ -195,27 +195,27 @@ public void close() { /** Send the header required to be sent after the socket is connected */ public void sendHeader() { - if(LOG) Log.w(TAG, "sendHeader"); - if(mState == STATE_INITIAL) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendHeader"); + if(STATE_INITIAL == mState) { try { - ByteBuffer buf = preparePacketHeader(PACKET_TYPE_HEADER, LONG_BYTES + INTEGER_BYTES); - buf.putLong(mFileLength); - buf.putInt(MAX_DATA_SIZE); + final ByteBuffer buf = this.preparePacketHeader(TrackProviderProto.PACKET_TYPE_HEADER, TrackProviderProto.LONG_BYTES + TrackProviderProto.INTEGER_BYTES); + buf.putLong(this.mFileLength); + buf.putInt(TrackProviderProto.MAX_DATA_SIZE); buf.flip(); while(buf.hasRemaining()) { - int res = Os.sendto(mSocket, buf, 0, null, 0); // sendto updates buffer position - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + final int res = Os.sendto(this.mSocket, buf, 0, null, 0); // sendto updates buffer position + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); } - mState = STATE_DATA; - if(LOG) Log.w(TAG, "sendHeader OK"); + this.mState = TrackProviderProto.STATE_DATA; + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendHeader OK"); - } catch(ErrnoException|SocketException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final ErrnoException | SocketException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); } - } else if(DEBUG_CHECKS) throw new AssertionError(mState); + } else if(TrackProviderProto.DEBUG_CHECKS) throw new AssertionError(this.mState); } /** @@ -229,12 +229,12 @@ public void sendHeader() { * @param data buffer to send. Should be properly flipped prior sending * @return request for the new seek position, or INVALID_SEEK_POS(==Long.MIN_VALUE) if none requested */ - public long sendData(@NonNull ByteBuffer data) { - SeekRequest request = sendData2(data); - if(request != null) { + public long sendData(@NonNull final ByteBuffer data) { + final SeekRequest request = this.sendData2(data); + if(null != request) { return request.offsetBytes; } - return INVALID_SEEK_POS; + return TrackProviderProto.INVALID_SEEK_POS; } /** @@ -248,62 +248,62 @@ public long sendData(@NonNull ByteBuffer data) { * @param data buffer to send. Should be properly flipped prior sending * @return request for the new seek position, or null if none requested */ - public @Nullable SeekRequest sendData2(@NonNull ByteBuffer data) { - if(LOG) Log.w(TAG, "sendData2 data.remaining=" + data.remaining()); - if(mState == STATE_DATA) { + public @Nullable SeekRequest sendData2(@NonNull final ByteBuffer data) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendData2 data.remaining=" + data.remaining()); + if(STATE_DATA == mState) { @SuppressWarnings("unused") int packetsSent = 0; - final int originalDataLimit = data.limit(); // Keep original limit as we'll modify it to send up to MAX_DATA_SIZE bytes per packet + int originalDataLimit = data.limit(); // Keep original limit as we'll modify it to send up to MAX_DATA_SIZE bytes per packet while(data.hasRemaining()) { try { int size = data.remaining(); - if(size > MAX_DATA_SIZE) { // Sending up to MAX_DATA_SIZE - size = MAX_DATA_SIZE; + if(MAX_DATA_SIZE < size) { // Sending up to MAX_DATA_SIZE + size = TrackProviderProto.MAX_DATA_SIZE; } data.limit(data.position() + size); - ByteBuffer buf = preparePacketHeader(PACKET_TYPE_DATA, size); + final ByteBuffer buf = this.preparePacketHeader(TrackProviderProto.PACKET_TYPE_DATA, size); buf.flip(); while(buf.hasRemaining()) { - int res = Os.sendto(mSocket, buf, 0, null, 0); - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + final int res = Os.sendto(this.mSocket, buf, 0, null, 0); + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); } while(data.hasRemaining()) { - int res = Os.sendto(mSocket, data, 0, null, 0); // data.position changed by # of bytes actually sent - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(data, res); + final int res = Os.sendto(this.mSocket, data, 0, null, 0); // data.position changed by # of bytes actually sent + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(data, res); } packetsSent++; buf.clear(); - } catch(ErrnoException ex) { + } catch(final ErrnoException ex) { if(ex.errno == OsConstants.ECONNRESET || ex.errno == OsConstants.EPIPE) throw new TrackProviderProtoClosed(ex); - if(LOG) Log.e(TAG, "", ex); + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); - } catch(SocketException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final SocketException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); } finally { data.limit(originalDataLimit); // Restore limit } try { - int fdsReady = Os.poll(mStructPollFds, 0); // Check for possible incoming packet header + final int fdsReady = Os.poll(this.mStructPollFds, 0); // Check for possible incoming packet header - if(fdsReady == 1) { - SeekRequest seekPosEncoded = readSeekRequest(true); // This shouldn't block as we checked we have some incoming data - if(seekPosEncoded != null) { + if(1 == fdsReady) { + final SeekRequest seekPosEncoded = this.readSeekRequest(true); // This shouldn't block as we checked we have some incoming data + if(null != seekPosEncoded) { return seekPosEncoded; // Got valid seek request, return it } } - } catch(ErrnoException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final ErrnoException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); } } - if(LOG) Log.w(TAG, "sendDataPackets OK packetsSent=" + packetsSent); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendDataPackets OK packetsSent=" + packetsSent); - } else if(DEBUG_CHECKS) throw new AssertionError(mState); + } else if(TrackProviderProto.DEBUG_CHECKS) throw new AssertionError(this.mState); return null; } @@ -313,15 +313,15 @@ public long sendData(@NonNull ByteBuffer data) { * @return request for the new seek position, or INVALID_SEEK_POS(==Long.MIN_VALUE) if none requested, socket closed, error happened, etc. */ public long sendEOFAndWaitForSeekOrClose() { - if(LOG) Log.w(TAG, "sendEOFAndWaitForSeekOrClose"); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendEOFAndWaitForSeekOrClose"); - SeekRequest seekRequest = sendEOFAndWaitForSeekOrClose2(); - if(seekRequest != null) { - if(LOG) Log.w(TAG, "sendEOFAndWaitForSeekOrClose got seek=>" + seekRequest.offsetBytes); + final SeekRequest seekRequest = this.sendEOFAndWaitForSeekOrClose2(); + if(null != seekRequest) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendEOFAndWaitForSeekOrClose got seek=>" + seekRequest.offsetBytes); return seekRequest.offsetBytes; } - if(LOG) Log.w(TAG, "sendEOFAndWaitForSeekOrClose DONE"); - return INVALID_SEEK_POS; + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendEOFAndWaitForSeekOrClose DONE"); + return TrackProviderProto.INVALID_SEEK_POS; } /** @@ -329,24 +329,24 @@ public long sendEOFAndWaitForSeekOrClose() { * @return request for the new seek position, or null if none requested, socket closed, error happened, etc. */ public @Nullable SeekRequest sendEOFAndWaitForSeekOrClose2() { - if(LOG) Log.w(TAG, "waitForSeekOrClose"); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "waitForSeekOrClose"); try { // Send EOF (empty data buffer) - ByteBuffer buf = preparePacketHeader(PACKET_TYPE_DATA, 0); + final ByteBuffer buf = this.preparePacketHeader(TrackProviderProto.PACKET_TYPE_DATA, 0); buf.flip(); while(buf.hasRemaining()) { - int res = Os.sendto(mSocket, buf, 0, null, 0); - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + final int res = Os.sendto(this.mSocket, buf, 0, null, 0); + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); } - } catch(ErrnoException|SocketException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final ErrnoException | SocketException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); } try { - return readSeekRequest(false); - } catch(TrackProviderProtoException ex) { + return this.readSeekRequest(false); + } catch(final TrackProviderProtoException ex) { return null; } } @@ -355,55 +355,55 @@ public long sendEOFAndWaitForSeekOrClose() { * Try to read Poweramp sends seek request. Blocks until socket has some data * @return request for the new seek position, or null if none requested */ - private @Nullable SeekRequest readSeekRequest(boolean noBlock) { - if(LOG) Log.w(TAG, "readSeekRequest"); + private @Nullable SeekRequest readSeekRequest(final boolean noBlock) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "readSeekRequest"); try { - ByteBuffer buf = mHeaderBuffer; + final ByteBuffer buf = this.mHeaderBuffer; buf.clear(); - buf.limit(MAX_PACKET_HEADER_SIZE); // Read just header + buf.limit(TrackProviderProto.MAX_PACKET_HEADER_SIZE); // Read just header - int res = Os.recvfrom(mSocket, buf, 0, null); - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + int res = Os.recvfrom(this.mSocket, buf, 0, null); + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); - if(res == MAX_PACKET_HEADER_SIZE) { - int type = getPacketType(buf); - int dataSize = getPacketDataSize(buf); - if(type == PACKET_TYPE_SEEK && dataSize >= LONG_BYTES) { - if(LOG) Log.w(TAG, "readSeekRequest got PACKET_TYPE_SEEK dataSize=>" + dataSize); + if(MAX_PACKET_HEADER_SIZE == res) { + final int type = TrackProviderProto.getPacketType(buf); + final int dataSize = TrackProviderProto.getPacketDataSize(buf); + if(PACKET_TYPE_SEEK == type && LONG_BYTES <= dataSize) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "readSeekRequest got PACKET_TYPE_SEEK dataSize=>" + dataSize); buf.limit(buf.limit() + dataSize); - res = Os.recvfrom(mSocket, buf, noBlock ? OsConstants.O_NONBLOCK : 0, null); // Read seek position - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + res = Os.recvfrom(this.mSocket, buf, noBlock ? OsConstants.O_NONBLOCK : 0, null); // Read seek position + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); - if(res >= LONG_BYTES) { - SeekRequest seekRequest = mTempSeekRequest; - seekRequest.offsetBytes = buf.getLong(PACKET_DATA_IX); - if(LOG) Log.w(TAG, "readSeekRequest got offsetBytes=>" + seekRequest.offsetBytes); - if(res >= LONG_BYTES + INTEGER_BYTES) { - seekRequest.ms = buf.getInt(PACKET_DATA_IX + LONG_BYTES); - if(LOG) Log.w(TAG, "readSeekRequest got ms=>" + seekRequest.ms); + if(LONG_BYTES <= res) { + final SeekRequest seekRequest = this.mTempSeekRequest; + seekRequest.offsetBytes = buf.getLong(TrackProviderProto.PACKET_DATA_IX); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "readSeekRequest got offsetBytes=>" + seekRequest.offsetBytes); + if(LONG_BYTES + TrackProviderProto.INTEGER_BYTES <= res) { + seekRequest.ms = buf.getInt(TrackProviderProto.PACKET_DATA_IX + TrackProviderProto.LONG_BYTES); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "readSeekRequest got ms=>" + seekRequest.ms); } else { seekRequest.ms = Integer.MIN_VALUE; } return seekRequest; - } else Log.e(TAG, "readSeekRequest FAIL recvfrom data res=" + res); + } else Log.e(TrackProviderProto.TAG, "readSeekRequest FAIL recvfrom data res=" + res); } else - Log.e(TAG, "readSeekRequest FAIL recvfrom type=" + type + " dataSize=" + dataSize); - } else if(res == 0) { + Log.e(TrackProviderProto.TAG, "readSeekRequest FAIL recvfrom type=" + type + " dataSize=" + dataSize); + } else if(0 == res) { // EOF - if(LOG) Log.w(TAG, "readSeekRequest EOF"); + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "readSeekRequest EOF"); return null; - } else Log.e(TAG, "readSeekRequest FAIL recvfrom res=" + res); - } catch(ErrnoException ex) { - if(LOG) Log.e(TAG, "", ex); + } else Log.e(TrackProviderProto.TAG, "readSeekRequest FAIL recvfrom res=" + res); + } catch(final ErrnoException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); if(ex.errno == OsConstants.ECONNRESET || ex.errno == OsConstants.EPIPE) throw new TrackProviderProtoClosed(ex); if(ex.errno == OsConstants.EAGAIN) { // Timed out return null; } throw new TrackProviderProtoException(ex); - } catch(SocketException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final SocketException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); } return null; @@ -414,18 +414,18 @@ public long sendEOFAndWaitForSeekOrClose() { * @param newPos if >= 0 - indicates a new byte position within the track, or <0 if the seek failed */ - public void sendSeekResult(long newPos) { - if(LOG) Log.w(TAG, "sendSeekResult newPos=" + newPos); - ByteBuffer buf = preparePacketHeader(PACKET_TYPE_SEEK_RES, LONG_BYTES); + public void sendSeekResult(final long newPos) { + if(TrackProviderProto.LOG) Log.w(TrackProviderProto.TAG, "sendSeekResult newPos=" + newPos); + final ByteBuffer buf = this.preparePacketHeader(TrackProviderProto.PACKET_TYPE_SEEK_RES, TrackProviderProto.LONG_BYTES); buf.putLong(newPos); buf.flip(); try { while(buf.hasRemaining()) { - int res = Os.sendto(mSocket, buf, 0, null, 0); - if(Build.VERSION.SDK_INT == 21) maybeUpdateBufferPosition(buf, res); + final int res = Os.sendto(this.mSocket, buf, 0, null, 0); + if(21 == Build.VERSION.SDK_INT) TrackProviderProto.maybeUpdateBufferPosition(buf, res); } - } catch(ErrnoException|SocketException ex) { - if(LOG) Log.e(TAG, "", ex); + } catch(final ErrnoException | SocketException ex) { + if(TrackProviderProto.LOG) Log.e(TrackProviderProto.TAG, "", ex); throw new TrackProviderProtoException(ex); } } @@ -433,12 +433,12 @@ public void sendSeekResult(long newPos) { /** * @return packetType > 0, or -1 on failure */ - private static int getPacketType(@NonNull ByteBuffer buf) { + private static int getPacketType(@NonNull final ByteBuffer buf) { // Packet header is TAG(4) + PACKET_TYPE(2) + DATA_SIZE(2) + DATA_SERIAL(4) => 12 - if(buf.limit() >= MAX_PACKET_HEADER_SIZE && buf.getInt(0) == PACKET_TAG) { - int type = buf.getShort(4); - int dataSize = getPacketDataSize(buf); - if(type > 0 && dataSize > 0) { + if(MAX_PACKET_HEADER_SIZE <= buf.limit() && PACKET_TAG == buf.getInt(0)) { + final int type = buf.getShort(4); + final int dataSize = TrackProviderProto.getPacketDataSize(buf); + if(0 < type && 0 < dataSize) { return type; } } @@ -448,13 +448,13 @@ private static int getPacketType(@NonNull ByteBuffer buf) { /** * @return packet data size */ - private static int getPacketDataSize(@NonNull ByteBuffer buf) { - return buf.getShort(PACKET_DATA_SIZE_IX); + private static int getPacketDataSize(@NonNull final ByteBuffer buf) { + return buf.getShort(TrackProviderProto.PACKET_DATA_SIZE_IX); } /** Required for Android 5.0.0 which doesn't update buffers */ - private static void maybeUpdateBufferPosition(ByteBuffer buffer, int bytesReadOrWritten) { - if(bytesReadOrWritten > 0) { + private static void maybeUpdateBufferPosition(final ByteBuffer buffer, final int bytesReadOrWritten) { + if(0 < bytesReadOrWritten) { buffer.position(bytesReadOrWritten + buffer.position()); } } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/plugin/PluginMsgHelper.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/plugin/PluginMsgHelper.java index cc61a1e4..7ee9669e 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/plugin/PluginMsgHelper.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/plugin/PluginMsgHelper.java @@ -26,13 +26,15 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -public class PluginMsgHelper { - public static class PluginMsgException extends RuntimeException { +public enum PluginMsgHelper { + ; + + public static class PluginMsgException extends RuntimeException { private static final long serialVersionUID = -5131019933670409856L; public PluginMsgException() {} - public PluginMsgException(@NonNull String msg) { + public PluginMsgException(@NonNull final String msg) { super(msg); } } @@ -41,11 +43,11 @@ public PluginMsgException(@NonNull String msg) { public static final int MSG_TAG = 0xF1F2F3F4; public static final int HEADER_SIZE_INTS = 8; public static final int MAX_SIZE_INTS = 1024; - public static final int MAX_SIZE_BYTES = MAX_SIZE_INTS * 4; - public static final int HEADER_SIZE_BYTES = HEADER_SIZE_INTS * 4; + public static final int MAX_SIZE_BYTES = PluginMsgHelper.MAX_SIZE_INTS * 4; + public static final int HEADER_SIZE_BYTES = PluginMsgHelper.HEADER_SIZE_INTS * 4; - public static int IX_PLUGIN_ID = 0; - public static int IX_PLUGIN_ID_INT = 0; + public static int IX_PLUGIN_ID; + public static int IX_PLUGIN_ID_INT; public static final int IX_TAG = 4 * 4; // 1 public static final int IX_MSG_ID = 5 * 4; // 2 public static final int IX_FLAGS = 6 * 4; // 3 @@ -63,39 +65,39 @@ public PluginMsgException(@NonNull String msg) { public static int MSG_ID_BROADCAST = -1; - public static int calcBufferSizeInts(int desiredSizeInts) { - return HEADER_SIZE_INTS + desiredSizeInts; + public static int calcBufferSizeInts(final int desiredSizeInts) { + return PluginMsgHelper.HEADER_SIZE_INTS + desiredSizeInts; } - public static int calcBufferSizeBytes(int desiredSizeBytes) { - return HEADER_SIZE_BYTES + desiredSizeBytes; + public static int calcBufferSizeBytes(final int desiredSizeBytes) { + return PluginMsgHelper.HEADER_SIZE_BYTES + desiredSizeBytes; } - private static void writeHeader(int @NonNull[] buf, int pluginID, int msgID, int flags, int desiredSizeInts) { + private static void writeHeader(final int @NonNull[] buf, final int pluginID, final int msgID, final int flags, final int desiredSizeInts) { buf[0] = pluginID; // 3 ints are zeros (reserved for Poweramp msg header). - buf[IX_TAG / 4] = MSG_TAG; - buf[IX_MSG_ID / 4] = msgID; - buf[IX_FLAGS / 4] = flags; - buf[IX_DATA_SIZE / 4] = desiredSizeInts * 4; + buf[PluginMsgHelper.IX_TAG / 4] = PluginMsgHelper.MSG_TAG; + buf[PluginMsgHelper.IX_MSG_ID / 4] = msgID; + buf[PluginMsgHelper.IX_FLAGS / 4] = flags; + buf[PluginMsgHelper.IX_DATA_SIZE / 4] = desiredSizeInts * 4; } - private static void writeHeader(@NonNull ByteBuffer buf, int pluginID, int msgID, int flags, int desiredSizeBytes) { + private static void writeHeader(@NonNull final ByteBuffer buf, final int pluginID, final int msgID, final int flags, final int desiredSizeBytes) { buf.putInt(pluginID); // 3 ints are zeros (reserved for Poweramp msg header). - buf.position(IX_TAG); - buf.putInt(MSG_TAG); + buf.position(PluginMsgHelper.IX_TAG); + buf.putInt(PluginMsgHelper.MSG_TAG); buf.putInt(msgID); buf.putInt(flags); buf.putInt(desiredSizeBytes); } - public static int @NonNull[] createIntMsgBuffer(int pluginID, int msgID, int flags, int desiredSizeInts) { - if(desiredSizeInts > MAX_SIZE_INTS) { - throw new PluginMsgException("bad desiredSizeInts=" + desiredSizeInts + " MAX_SIZE_INTS=" + MAX_SIZE_INTS); + public static int @NonNull[] createIntMsgBuffer(final int pluginID, final int msgID, final int flags, final int desiredSizeInts) { + if(MAX_SIZE_INTS < desiredSizeInts) { + throw new PluginMsgException("bad desiredSizeInts=" + desiredSizeInts + " MAX_SIZE_INTS=" + PluginMsgHelper.MAX_SIZE_INTS); } - int[] buf = new int[calcBufferSizeInts(desiredSizeInts)]; - writeHeader(buf, pluginID, msgID, flags, desiredSizeInts); + final int[] buf = new int[PluginMsgHelper.calcBufferSizeInts(desiredSizeInts)]; + PluginMsgHelper.writeHeader(buf, pluginID, msgID, flags, desiredSizeInts); return buf; } @@ -103,48 +105,48 @@ private static void writeHeader(@NonNull ByteBuffer buf, int pluginID, int msgID * NOTE: returned ByteBuffer is positioned to the first data position
* NOTE: direct buffer makes no sense in our case and is slower
*/ - public static @NonNull ByteBuffer createBufferMsgBuffer(int pluginID, int msgID, int flags, int desiredSizeBytes) { - if(desiredSizeBytes > MAX_SIZE_BYTES) { - throw new PluginMsgException("bad desiredSizeBytes=" + MAX_SIZE_BYTES + " MAX_SIZE_BYTES=" + MAX_SIZE_BYTES); + public static @NonNull ByteBuffer createBufferMsgBuffer(final int pluginID, final int msgID, final int flags, final int desiredSizeBytes) { + if(MAX_SIZE_BYTES < desiredSizeBytes) { + throw new PluginMsgException("bad desiredSizeBytes=" + PluginMsgHelper.MAX_SIZE_BYTES + " MAX_SIZE_BYTES=" + PluginMsgHelper.MAX_SIZE_BYTES); } - ByteBuffer buf = ByteBuffer.allocate(calcBufferSizeBytes(desiredSizeBytes)); + final ByteBuffer buf = ByteBuffer.allocate(PluginMsgHelper.calcBufferSizeBytes(desiredSizeBytes)); buf.order(ByteOrder.LITTLE_ENDIAN); - writeHeader(buf, pluginID, msgID, flags, desiredSizeBytes); + PluginMsgHelper.writeHeader(buf, pluginID, msgID, flags, desiredSizeBytes); return buf; } - public static @NonNull String msgBufferAsString(int @Nullable[] buf) { - if(buf == null) { + public static @NonNull String msgBufferAsString(final int @Nullable[] buf) { + if(null == buf) { return "null"; } - if(buf.length < HEADER_SIZE_INTS) { + if(HEADER_SIZE_INTS > buf.length) { throw new PluginMsgException("bad buf length=" + buf.length); } - return toString(buf); + return PluginMsgHelper.toString(buf); } - public static @NonNull String msgBufferAsString(@NonNull ByteBuffer buf) { - if(buf.capacity() < HEADER_SIZE_BYTES) { + public static @NonNull String msgBufferAsString(@NonNull final ByteBuffer buf) { + if(HEADER_SIZE_BYTES > buf.capacity()) { throw new PluginMsgException("bad buf capacity=" + buf.capacity()); } - int pos = buf.position(); + final int pos = buf.position(); buf.position(0); - IntBuffer intBuf = buf.asIntBuffer(); + final IntBuffer intBuf = buf.asIntBuffer(); buf.position(pos); - int[] ar = new int[intBuf.capacity()]; + final int[] ar = new int[intBuf.capacity()]; intBuf.get(ar); - return toString(ar); + return PluginMsgHelper.toString(ar); } @SuppressWarnings("null") - private static @NonNull String toString(int @NonNull[] array) { - if (array == null) { + private static @NonNull String toString(final int @NonNull[] array) { + if (null == array) { return "null"; } - if (array.length == 0) { + if (0 == array.length) { return "[]"; } - StringBuilder sb = new StringBuilder(array.length * 6); + final StringBuilder sb = new StringBuilder(array.length * 6); sb.append('['); sb.append(array[0]); for (int i = 1; i < array.length; i++) { diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/BaseWidgetProvider.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/BaseWidgetProvider.java index c3c6460f..4d42f59a 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/BaseWidgetProvider.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/BaseWidgetProvider.java @@ -30,15 +30,17 @@ public static class WidgetContext { public int id; } - public static final class ShuffleModeV140 { - public static final int SHUFFLE_NONE = 0; + public enum ShuffleModeV140 { + ; + public static final int SHUFFLE_NONE = 0; public static final int SHUFFLE_ALL = 1; public static final int SHUFFLE_IN_CAT = 2; public static final int SHUFFLE_HIER = 3; } - public static final class RepeatModeV140 { - public static final int REPEAT_NONE = 0; + public enum RepeatModeV140 { + ; + public static final int REPEAT_NONE = 0; public static final int REPEAT_ALL = 1; public static final int REPEAT_SONG = 2; public static final int REPEAT_CAT = 3; @@ -66,22 +68,22 @@ public static final class RepeatModeV140 { // NOTE: called by system @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - if(appWidgetIds.length == 0) { - if(LOG) Log.e(TAG, "no widget ids"); + public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) { + if(0 == appWidgetIds.length) { + if(BaseWidgetProvider.LOG) Log.e(BaseWidgetProvider.TAG, "no widget ids"); return; } - if(LOG) Log.w(TAG, "onUpdate ids=" + Arrays.toString(appWidgetIds)); + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "onUpdate ids=" + Arrays.toString(appWidgetIds)); - WidgetUpdater widgetUpdater = getWidgetUpdater(context); + final WidgetUpdater widgetUpdater = this.getWidgetUpdater(context); try { widgetUpdater.updateSafe(this, true, true, appWidgetIds); // Immediate update, ignores power state - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(BaseWidgetProvider.TAG, "", th); } } @@ -89,62 +91,62 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] a // THREADING: any @Override - public @Nullable WidgetUpdateData pushUpdate(Context context, @NonNull SharedPreferences prefs, int @Nullable[] ids, - boolean mediaRemoved, @NonNull WidgetUpdateData data + public @Nullable WidgetUpdateData pushUpdate(final Context context, @NonNull final SharedPreferences prefs, int @Nullable[] ids, + final boolean mediaRemoved, @NonNull final WidgetUpdateData data ) { - AppWidgetManager appWidgetManager = mAppWidgetManager; - if(appWidgetManager == null) { - appWidgetManager = mAppWidgetManager = AppWidgetManager.getInstance(context); + AppWidgetManager appWidgetManager = this.mAppWidgetManager; + if(null == appWidgetManager) { + appWidgetManager = this.mAppWidgetManager = AppWidgetManager.getInstance(context); } - if(ids == null) { + if(null == ids) { try { // java.lang.RuntimeException: system server dead? at android.appwidget.AppWidgetManager.getAppWidgetIds(AppWidgetManager.java:492) at com.maxmpz.audioplayer.widgetpackcommon.BaseWidgetProvider (":139) long start; - if(LOG) start = System.nanoTime(); + if(BaseWidgetProvider.LOG) start = System.nanoTime(); - if(mComponentName == null) { - mComponentName = new ComponentName(context, this.getClass()); + if(null == mComponentName) { + this.mComponentName = new ComponentName(context, getClass()); } - ids = appWidgetManager.getAppWidgetIds(mComponentName); + ids = appWidgetManager.getAppWidgetIds(this.mComponentName); - if(LOG) Log.w(TAG, "pushUpdate getAppWidgetIds in=" + (System.nanoTime() - start) / 1000 + " =>ids=" + Arrays.toString(ids) + " me=" + this); - } catch(Exception ex) { - Log.e(TAG, "", ex); + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "pushUpdate getAppWidgetIds in=" + (System.nanoTime() - start) / 1000 + " =>ids=" + Arrays.toString(ids) + " me=" + this); + } catch(final Exception ex) { + Log.e(BaseWidgetProvider.TAG, "", ex); } } - if(ids == null || ids.length == 0) { - if(LOG) Log.w(TAG, "pushUpdate FAIL no ids me=" + this); + if(null == ids || 0 == ids.length) { + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "pushUpdate FAIL no ids me=" + this); return null; } - if(LOG) Log.w(TAG, "pushUpdate ids to update: " + Arrays.toString(ids) + " data=" + data + " me=" + this); + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "pushUpdate ids to update: " + Arrays.toString(ids) + " data=" + data + " me=" + this); try { - for(int id : ids) { - if(id == 0) { // Skip possible zero ids - if(LOG) Log.w(TAG, "pushUpdate SKIP as ids[0] me=" + this); + for(final int id : ids) { + if(0 == id) { // Skip possible zero ids + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "pushUpdate SKIP as ids[0] me=" + this); break; } - RemoteViews rv = update(context, data, prefs, id); // java.lang.RuntimeException: Could not write bitmap to parcel blob. + final RemoteViews rv = this.update(context, data, prefs, id); // java.lang.RuntimeException: Could not write bitmap to parcel blob. appWidgetManager.updateAppWidget(id, rv); } - } catch(Exception ex) { - Log.e(TAG, "", ex); + } catch(final Exception ex) { + Log.e(BaseWidgetProvider.TAG, "", ex); } return data; } // NOTE: further overridden - protected boolean getAANoAnimState(WidgetUpdateData data, WidgetContext widgetCtx) { + protected boolean getAANoAnimState(final WidgetUpdateData data, final WidgetContext widgetCtx) { if(data.albumArtNoAnim || widgetCtx.lastAATimeStamp == data.albumArtTimestamp - || data.hasTrack && (data.flags & PowerampAPI.Track.Flags.FLAG_FIRST_IN_PLAYER_SESSION) != 0 + || data.hasTrack && 0 != (data.flags & PowerampAPI.Track.Flags.FLAG_FIRST_IN_PLAYER_SESSION) ) { - if(LOG) Log.w(TAG, "getAANoAnimState =>true data.albumArtNoAnim=" + data.albumArtNoAnim + " same ts=" + (widgetCtx.lastAATimeStamp == data.albumArtTimestamp) + + if(BaseWidgetProvider.LOG) Log.w(BaseWidgetProvider.TAG, "getAANoAnimState =>true data.albumArtNoAnim=" + data.albumArtNoAnim + " same ts=" + (widgetCtx.lastAATimeStamp == data.albumArtTimestamp) + " FLAG_FIRST_IN_PLAYER_SESSION=" + (data.flags & PowerampAPI.Track.Flags.FLAG_FIRST_IN_PLAYER_SESSION) + " bitmap=" + data.albumArtBitmap); return true; @@ -153,12 +155,12 @@ protected boolean getAANoAnimState(WidgetUpdateData data, WidgetContext widgetCt } - public static String getReadable(String title, String unknown) { - return getReadable(title, unknown, false); + public static String getReadable(final String title, final String unknown) { + return BaseWidgetProvider.getReadable(title, unknown, false); } - public static String getReadable(String title, String unknown, boolean allowEmpty) { - if(title != null && (allowEmpty || title.length() > 0)) { + public static String getReadable(final String title, final String unknown, final boolean allowEmpty) { + if(null != title && (allowEmpty || 0 < title.length())) { return title; } return unknown; diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/IWidgetUpdater.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/IWidgetUpdater.java index 70dc5241..e517a5c7 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/IWidgetUpdater.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/IWidgetUpdater.java @@ -26,7 +26,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import org.eclipse.jdt.annotation.Nullable; public interface IWidgetUpdater { - public @Nullable WidgetUpdateData pushUpdate(Context context, @NonNull SharedPreferences prefs, int @Nullable[] ids, + @Nullable WidgetUpdateData pushUpdate(Context context, @NonNull SharedPreferences prefs, int @Nullable[] ids, boolean mediaRemoved, @NonNull WidgetUpdateData data ); } diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdateData.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdateData.java index ab448b4c..7c10574d 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdateData.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdateData.java @@ -59,10 +59,10 @@ public class WidgetUpdateData { @Override public String toString() { - return super.toString() + " hasTrack=" + hasTrack + " title=" + title + " album=" + album + " artist=" + artist + " supportsCatNav=" + supportsCatNav + - " posInList=" + posInList + " listSize=" + listSize + " flags=0x" + Integer.toHexString(flags) + " albumArtBitmap=" + albumArtBitmap + - " albumArtTimestamp=" + albumArtTimestamp + " albumArtSource=" + albumArtSource + - " playing=" + playing + " shuffle=" + shuffle + " repeat=" + repeat; + return super.toString() + " hasTrack=" + this.hasTrack + " title=" + this.title + " album=" + this.album + " artist=" + this.artist + " supportsCatNav=" + this.supportsCatNav + + " posInList=" + this.posInList + " listSize=" + this.listSize + " flags=0x" + Integer.toHexString(this.flags) + " albumArtBitmap=" + this.albumArtBitmap + + " albumArtTimestamp=" + this.albumArtTimestamp + " albumArtSource=" + this.albumArtSource + + " playing=" + this.playing + " shuffle=" + this.shuffle + " repeat=" + this.repeat; } /** @@ -70,12 +70,12 @@ public String toString() { * Same for repeat/shuffle, playing state */ public void resetTrackData() { - if(LOG) Log.w(TAG, "resetTrackData", new Exception()); - hasTrack = false; - title = album = artist = null; - supportsCatNav = false; - posInList = 0; - listSize = 0; + if(WidgetUpdateData.LOG) Log.w(WidgetUpdateData.TAG, "resetTrackData", new Exception()); + this.hasTrack = false; + this.title = this.album = this.artist = null; + this.supportsCatNav = false; + this.posInList = 0; + this.listSize = 0; // NOTE: not resetting album art, repeat/shuffle, nor playing } } \ No newline at end of file diff --git a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdater.java b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdater.java index aaf7943b..f3346de0 100644 --- a/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdater.java +++ b/poweramp_api_lib/src/main/java/com/maxmpz/poweramp/widgetpackcommon/WidgetUpdater.java @@ -56,7 +56,7 @@ public abstract class WidgetUpdater { private static boolean sUpdatedOnce; public static final IntentFilter sTrackFilter = new IntentFilter(PowerampAPI.ACTION_TRACK_CHANGED); - public static final IntentFilter sAAFilter = USE_AA_EVENT ? new IntentFilter(PowerampAPI.ACTION_AA_CHANGED) : null; + public static final IntentFilter sAAFilter = WidgetUpdater.USE_AA_EVENT ? new IntentFilter(PowerampAPI.ACTION_AA_CHANGED) : null; public static final IntentFilter sStatusFilter = new IntentFilter(PowerampAPI.ACTION_STATUS_CHANGED); public static final IntentFilter sModeFilter = new IntentFilter(PowerampAPI.ACTION_PLAYING_MODE_CHANGED); @@ -72,27 +72,27 @@ public abstract class WidgetUpdater { /** * Used by PS to push updates, usually all providers added in constructor of the derived class */ - public WidgetUpdater(Context context) { + protected WidgetUpdater(final Context context) { long start; - if(LOG) start = System.nanoTime(); + if(WidgetUpdater.LOG) start = System.nanoTime(); - PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - if(powerManager == null) throw new AssertionError(); - mPowerManager = powerManager; + final PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + if(null == powerManager) throw new AssertionError(); + this.mPowerManager = powerManager; - mContext = context; // NOTE: PS context ATM + this.mContext = context; // NOTE: PS context ATM - if(LOG) Log.w(TAG, "ctor in=" + (System.nanoTime() - start) / 1000); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "ctor in=" + (System.nanoTime() - start) / 1000); } /** * Per-single provider ctor, used for cases when provider is called by system */ - public WidgetUpdater(Context context, @NonNull BaseWidgetProvider prov) { + protected WidgetUpdater(final Context context, @NonNull final BaseWidgetProvider prov) { this(context); - synchronized(mLock) { - mProviders.add(prov); + synchronized(this.mLock) { + this.mProviders.add(prov); } } @@ -101,37 +101,37 @@ public WidgetUpdater(Context context, @NonNull BaseWidgetProvider prov) { * Called just for given provider */ // THREADING: any - public void updateSafe(@NonNull BaseWidgetProvider provider, boolean ignorePowerState, boolean updateByOs, int[] appWidgetIds) { - if(LOG) Log.w(TAG, "updateSafe th=" + Thread.currentThread() + " provider=" + provider); + public void updateSafe(@NonNull final BaseWidgetProvider provider, final boolean ignorePowerState, final boolean updateByOs, final int[] appWidgetIds) { + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "updateSafe th=" + Thread.currentThread() + " provider=" + provider); - synchronized(mLock) { - if(!ignorePowerState && !mPowerManager.isInteractive() && sUpdatedOnce){ - if(LOG) Log.e(TAG, "skipping update, screen is off"); + synchronized(this.mLock) { + if(!ignorePowerState && !this.mPowerManager.isInteractive() && WidgetUpdater.sUpdatedOnce){ + if(WidgetUpdater.LOG) Log.e(WidgetUpdater.TAG, "skipping update, screen is off"); return; } - WidgetUpdateData data = generateUpdateData(mContext); + final WidgetUpdateData data = this.generateUpdateData(this.mContext); - if(LOG) Log.w(TAG, "========== updateSafe UPDATE data=" + data); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "========== updateSafe UPDATE data=" + data); - pushUpdateCore(data, appWidgetIds); + this.pushUpdateCore(data, appWidgetIds); } - if(LOG) Log.w(TAG, "update done "); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "update done "); } - private void pushUpdateCore(@NonNull WidgetUpdateData data, int[] ids) { - if(LOG) Log.w(TAG, "pushUpdateCore ids=" + Arrays.toString(ids) + " data=" + data + " mProviders.length=" + mProviders.size()); + private void pushUpdateCore(@NonNull final WidgetUpdateData data, final int[] ids) { + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "pushUpdateCore ids=" + Arrays.toString(ids) + " data=" + data + " mProviders.length=" + this.mProviders.size()); - SharedPreferences prefs = getCachedSharedPreferences(mContext); + final SharedPreferences prefs = WidgetUpdater.getCachedSharedPreferences(this.mContext); - for(IWidgetUpdater prov : mProviders) { - prov.pushUpdate(mContext, prefs, ids, false, data); // Media never removed, not changing signature for now + for(final IWidgetUpdater prov : this.mProviders) { + prov.pushUpdate(this.mContext, prefs, ids, false, data); // Media never removed, not changing signature for now } - if(data.hasTrack && !sUpdatedOnce) { - if(LOG) Log.w(TAG, "pushUpdateCore sUpdatedOnce=>true"); - sUpdatedOnce = true; + if(data.hasTrack && !WidgetUpdater.sUpdatedOnce) { + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "pushUpdateCore sUpdatedOnce=>true"); + WidgetUpdater.sUpdatedOnce = true; } } @@ -139,19 +139,19 @@ private void pushUpdateCore(@NonNull WidgetUpdateData data, int[] ids) { * Called by ExternalAPI * @return true if update happened, false if power state doesn't allow update now */ - public boolean updateDirectSafe(@NonNull WidgetUpdateData data, boolean ignorePowerState, boolean isScreenOn) { - synchronized(mLock) { - if(!ignorePowerState && !isScreenOn && sUpdatedOnce){ - if(LOG) Log.e(TAG, "updateDirectSafe skipping update, screen is off"); + public boolean updateDirectSafe(@NonNull final WidgetUpdateData data, final boolean ignorePowerState, final boolean isScreenOn) { + synchronized(this.mLock) { + if(!ignorePowerState && !isScreenOn && WidgetUpdater.sUpdatedOnce){ + if(WidgetUpdater.LOG) Log.e(WidgetUpdater.TAG, "updateDirectSafe skipping update, screen is off"); return false; } - if(LOG) Log.w(TAG, "updateDirectSafe data=" + data + " th=" + Thread.currentThread()); // + " extras=" + intent == null ? null : Arrays.toString(intent.getExtras().keySet().toArray(new String[]{}))); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "updateDirectSafe data=" + data + " th=" + Thread.currentThread()); // + " extras=" + intent == null ? null : Arrays.toString(intent.getExtras().keySet().toArray(new String[]{}))); - pushUpdateCore(data, null); + this.pushUpdateCore(data, null); } - if(LOG) Log.w(TAG, "update done "); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "update done "); return true; } @@ -160,18 +160,18 @@ public boolean updateDirectSafe(@NonNull WidgetUpdateData data, boolean ignorePo // from context 2 times // THREADING: any @SuppressWarnings("null") - public static @NonNull SharedPreferences getCachedSharedPreferences(Context context) { - SharedPreferences cachedPrefs = sCachedPrefs; - if(cachedPrefs == null) { + public static @NonNull SharedPreferences getCachedSharedPreferences(final Context context) { + SharedPreferences cachedPrefs = WidgetUpdater.sCachedPrefs; + if(null == cachedPrefs) { // NOTE: getting Poweramp shared prefs implementation via explicit app context - Context app = context.getApplicationContext(); - cachedPrefs = sCachedPrefs = app.getSharedPreferences(WIDGETS_PREFS_NAME, 0); + final Context app = context.getApplicationContext(); + cachedPrefs = WidgetUpdater.sCachedPrefs = app.getSharedPreferences(WidgetUpdater.WIDGETS_PREFS_NAME, 0); } return cachedPrefs; } /** NOTE: we're using #WIDGTS_PREFS_NAME now for widgets, but we still expose previous name to allow prefs code to migrate */ - public static String getOldSharedPreferencesName(Context context) { + public static String getOldSharedPreferencesName(final Context context) { return context.getPackageName() + "_appwidgets"; } @@ -185,30 +185,30 @@ public static String getOldSharedPreferencesName(Context context) { * Generates WidgetUpdateData from sticky intents */ // Data should be always the same for any type of widgets as data is reused by other widgets, thus method is final. - public @NonNull WidgetUpdateData generateUpdateData(Context context) { - WidgetUpdateData data = new WidgetUpdateData(); + public @NonNull WidgetUpdateData generateUpdateData(final Context context) { + final WidgetUpdateData data = new WidgetUpdateData(); - if(ALWAYS_USE_PERSISTANT_DATA) { + if(WidgetUpdater.ALWAYS_USE_PERSISTANT_DATA) { // Still check for actual playing status, as persistent data is stored per track change, thus never reflects playing state // Do it before loadDefaultOrPersistantUpdateData - getPlayingState(context, data); + this.getPlayingState(context, data); - loadDefaultOrPersistantUpdateData(context, data); + this.loadDefaultOrPersistantUpdateData(context, data); return data; } - Bundle track; + final Bundle track; - Intent trackIntent = context.registerReceiver(null, WidgetUpdater.sTrackFilter); + final Intent trackIntent = context.registerReceiver(null, sTrackFilter); - if(LOG) Log.w(TAG, "generateUpdateData trackIntent=" + trackIntent); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "generateUpdateData trackIntent=" + trackIntent); - if(trackIntent != null) { + if(null != trackIntent) { track = trackIntent.getParcelableExtra(PowerampAPI.EXTRA_TRACK); - if(track != null) { + if(null != track) { data.hasTrack = true; data.title = track.getString(PowerampAPI.Track.TITLE); data.album = track.getString(PowerampAPI.Track.ALBUM); @@ -217,15 +217,15 @@ public static String getOldSharedPreferencesName(Context context) { data.posInList = track.getInt(PowerampAPI.Track.POS_IN_LIST); data.supportsCatNav = track.getBoolean(PowerampAPI.Track.SUPPORTS_CAT_NAV); data.flags = track.getInt(PowerampAPI.Track.FLAGS); - if(LOG) Log.w(TAG, "received trackIntent data=" + data); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "received trackIntent data=" + data); } else { - loadDefaultOrPersistantUpdateData(context, data); + this.loadDefaultOrPersistantUpdateData(context, data); return data; } } else { // No any intent stored, need to get some defaults or previously saved persistent data - loadDefaultOrPersistantUpdateData(context, data); + this.loadDefaultOrPersistantUpdateData(context, data); return data; } @@ -244,28 +244,28 @@ public static String getOldSharedPreferencesName(Context context) { // } // } - getPlayingState(context, data); + this.getPlayingState(context, data); - Intent modeIntent = context.registerReceiver(null, WidgetUpdater.sModeFilter); - if(modeIntent != null) { + final Intent modeIntent = context.registerReceiver(null, sModeFilter); + if(null != modeIntent) { data.shuffle = modeIntent.getIntExtra(PowerampAPI.EXTRA_SHUFFLE, PowerampAPI.ShuffleMode.SHUFFLE_NONE); data.repeat = modeIntent.getIntExtra(PowerampAPI.EXTRA_REPEAT, PowerampAPI.RepeatMode.REPEAT_NONE); - if(LOG) Log.w(TAG, "repeat=" + data.repeat + " shuffle=" + data.shuffle); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "repeat=" + data.repeat + " shuffle=" + data.shuffle); } return data; } @SuppressWarnings("static-method") - private void getPlayingState(Context context, @NonNull WidgetUpdateData data) { - Intent statusIntent = context.registerReceiver(null, WidgetUpdater.sStatusFilter); - if(statusIntent != null) { + private void getPlayingState(final Context context, @NonNull final WidgetUpdateData data) { + final Intent statusIntent = context.registerReceiver(null, sStatusFilter); + if(null != statusIntent) { - boolean paused = statusIntent.getBooleanExtra(PowerampAPI.EXTRA_PAUSED, true); + final boolean paused = statusIntent.getBooleanExtra(PowerampAPI.EXTRA_PAUSED, true); data.playing = !paused; data.apiVersion = statusIntent.getIntExtra(PowerampAPI.EXTRA_API_VERSION, 0); - if(LOG) Log.w(TAG, "getPlayingState statusIntent=" + statusIntent + " paused=" + paused + " playing=" + data.playing); - } else if(LOG) Log.e(TAG, "getPlayingState statusIntent==null"); + if(WidgetUpdater.LOG) Log.w(WidgetUpdater.TAG, "getPlayingState statusIntent=" + statusIntent + " paused=" + paused + " playing=" + data.playing); + } else if(WidgetUpdater.LOG) Log.e(WidgetUpdater.TAG, "getPlayingState statusIntent==null"); } } diff --git a/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/LyricsRequestReceiver.kt b/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/LyricsRequestReceiver.kt index 250ebfab..0f5c0210 100644 --- a/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/LyricsRequestReceiver.kt +++ b/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/LyricsRequestReceiver.kt @@ -73,7 +73,7 @@ class LyricsRequestReceiver : BroadcastReceiver() { // NOTE: if it's a stream, we won't get durationMs and it may be generally harder to guess/search/load // lyrics for such stream "tracks" val isStream = fileType == PowerampAPI.Track.FileType.TYPE_STREAM - if(isStream && durationMs <= 0) durationMs = 60 * 1000; // Let's use some fake duration for our generateFakeLyrics + if(isStream && durationMs <= 0) durationMs = 60 * 1000 // Let's use some fake duration for our generateFakeLyrics val debugLine = "ACTION_NEED_LYRICS realId=$realId title=$title album=$album artist=$artist durationMs=$durationMs" DebugLines.addDebugLine(debugLine) diff --git a/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/MainActivity.kt b/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/MainActivity.kt index 974a3c1d..06b9757e 100644 --- a/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/MainActivity.kt +++ b/poweramp_lyrics_plugin_example/src/main/java/com/maxmpz/poweramplyricspluginexample/MainActivity.kt @@ -60,9 +60,9 @@ class MainActivity : Activity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) logTv = findViewById(R.id.log) - logTv?.setMovementMethod(ScrollingMovementMethod()) + logTv?.movementMethod = ScrollingMovementMethod() - val intent = getIntent() + val intent = intent if(intent != null && intent.action == PowerampAPI.Lyrics.ACTION_LYRICS_LINK && !intent.getBooleanExtra("__processed", false) ) { @@ -126,7 +126,7 @@ class MainActivity : Activity() { val lrc = trackId % 3 != 0L // Generate non-lrc for third of realIds val isStream = fileType == PowerampAPI.Track.FileType.TYPE_STREAM - if(isStream && durationMs <= 0) durationMs = 60 * 1000; // Let's use some fake duration for our generateFakeLyrics + if(isStream && durationMs <= 0) durationMs = 60 * 1000 // Let's use some fake duration for our generateFakeLyrics DebugLines.addDebugLine("generating lyrics for trackId=$trackId lrc=$lrc title=$title artist=$artist album=$album" + " dur=$durationMs ") @@ -134,7 +134,7 @@ class MainActivity : Activity() { val lyrics = generateFakeLyrics(lrc, "DIRECT:$title", artist, album, durationMs) // Inject some info line for even ids - val infoLine: String? = "DIRECTLY updated lyrics by Poweramp Plugin Example (realId=$trackId)" + val infoLine: String = "DIRECTLY updated lyrics by Poweramp Plugin Example (realId=$trackId)" if(sendLyricsResponse(this@MainActivity, trackId, lyrics, infoLine)) { error = null diff --git a/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/ExampleProvider.java b/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/ExampleProvider.java index 8eea379e..19a64a1d 100644 --- a/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/ExampleProvider.java +++ b/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/ExampleProvider.java @@ -20,8 +20,6 @@ import android.os.ProxyFileDescriptorCallback; import android.os.storage.StorageManager; import android.provider.DocumentsContract; -import android.provider.DocumentsContract.Root; -import android.provider.DocumentsContract.Document; import android.provider.DocumentsProvider; import android.provider.MediaStore; import android.system.ErrnoException; @@ -104,7 +102,7 @@ public class ExampleProvider extends DocumentsProvider { private static final long DUBSTEP_FAKE_FLAC_SIZE = 14000000; // ~116 bytes per ms in the real bensound-dubstep.flac, but "fake" value is an approximation - private static final long DUBSTEP_FAKE_AVERAGE_BYTES_PER_MS = Math.round((float)DUBSTEP_FAKE_FLAC_SIZE / (float) DUBSTEP_DURATION_MS); + private static final long DUBSTEP_FAKE_AVERAGE_BYTES_PER_MS = 112; /** If > 0, we'll force-stop the playback after these bytes played. Works for seekable sockets/PA protocol */ private static final long DEBUG_STOP_PROTOCOL_AFTER_BYTES = 0; // e.g. = 500000 @@ -120,23 +118,23 @@ public class ExampleProvider extends DocumentsProvider { /** Default columns returned for roots */ - private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { - Root.COLUMN_ROOT_ID, - Root.COLUMN_TITLE, - Root.COLUMN_SUMMARY, - Root.COLUMN_FLAGS, - Root.COLUMN_ICON, - Root.COLUMN_DOCUMENT_ID, + private static final String[] DEFAULT_ROOT_PROJECTION = { + DocumentsContract.Root.COLUMN_ROOT_ID, + DocumentsContract.Root.COLUMN_TITLE, + DocumentsContract.Root.COLUMN_SUMMARY, + DocumentsContract.Root.COLUMN_FLAGS, + DocumentsContract.Root.COLUMN_ICON, + DocumentsContract.Root.COLUMN_DOCUMENT_ID, }; /** Default columns returned for documents - folders and tracks (not including metadata) */ - private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { - Document.COLUMN_DOCUMENT_ID, - Document.COLUMN_MIME_TYPE, - Document.COLUMN_DISPLAY_NAME, - Document.COLUMN_LAST_MODIFIED, - Document.COLUMN_FLAGS, - Document.COLUMN_SIZE, + private static final String[] DEFAULT_DOCUMENT_PROJECTION = { + DocumentsContract.Document.COLUMN_DOCUMENT_ID, + DocumentsContract.Document.COLUMN_MIME_TYPE, + DocumentsContract.Document.COLUMN_DISPLAY_NAME, + DocumentsContract.Document.COLUMN_LAST_MODIFIED, + DocumentsContract.Document.COLUMN_FLAGS, + DocumentsContract.Document.COLUMN_SIZE, }; /** @@ -149,21 +147,21 @@ public class ExampleProvider extends DocumentsProvider { * NOTE: if TITLE and DURATION are missing, Poweramp also won't use thumbnail API (even if FLAG_SUPPORTS_THUMBNAIL is set). Instead Poweramp reads cover directly * from track (via another openDocument call) */ - private static final String[] DEFAULT_TRACK_AND_METADATA_PROJECTION = new String[] { - Document.COLUMN_DOCUMENT_ID, - Document.COLUMN_MIME_TYPE, - Document.COLUMN_DISPLAY_NAME, - Document.COLUMN_LAST_MODIFIED, - Document.COLUMN_FLAGS, - Document.COLUMN_SIZE, + private static final String[] DEFAULT_TRACK_AND_METADATA_PROJECTION = { + DocumentsContract.Document.COLUMN_DOCUMENT_ID, + DocumentsContract.Document.COLUMN_MIME_TYPE, + DocumentsContract.Document.COLUMN_DISPLAY_NAME, + DocumentsContract.Document.COLUMN_LAST_MODIFIED, + DocumentsContract.Document.COLUMN_FLAGS, + DocumentsContract.Document.COLUMN_SIZE, MediaStore.MediaColumns.TITLE, - MediaStore.Audio.AudioColumns.DURATION, - MediaStore.Audio.AudioColumns.ARTIST, - MediaStore.Audio.AudioColumns.ALBUM, + MediaStore.MediaColumns.DURATION, + MediaStore.MediaColumns.ARTIST, + MediaStore.MediaColumns.ALBUM, MediaStore.Audio.AudioColumns.YEAR, TrackProviderConsts.COLUMN_ALBUM_ARTIST, - MediaStore.Audio.AudioColumns.COMPOSER, + MediaStore.MediaColumns.COMPOSER, TrackProviderConsts.COLUMN_GENRE, MediaStore.Audio.AudioColumns.TRACK, TrackProviderConsts.COLUMN_TRACK_ALT, @@ -181,69 +179,69 @@ public class ExampleProvider extends DocumentsProvider { public boolean onCreate() { // Code to retrieve own apk install time. We use this here as lastModified. Not needed for real providers which can retrieve lastModified from the // content itself (either from network or filesystem) - PackageManager pm = getContext().getPackageManager(); + final PackageManager pm = this.getContext().getPackageManager(); try { - PackageInfo pakInfo = pm.getPackageInfo(getContext().getApplicationInfo().packageName, 0); - mApkInstallTime = pakInfo.lastUpdateTime > 0 ? pakInfo.lastUpdateTime : pakInfo.firstInstallTime; + final PackageInfo pakInfo = pm.getPackageInfo(this.getContext().getApplicationInfo().packageName, 0); + this.mApkInstallTime = 0 < pakInfo.lastUpdateTime ? pakInfo.lastUpdateTime : pakInfo.firstInstallTime; - if(LOG) Log.w(TAG, "onCreate mApkInstallTime=" + mApkInstallTime); - } catch(PackageManager.NameNotFoundException ex) { - Log.e(TAG, "", ex); - mApkInstallTime = System.currentTimeMillis(); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "onCreate mApkInstallTime=" + this.mApkInstallTime); + } catch(final PackageManager.NameNotFoundException ex) { + Log.e(ExampleProvider.TAG, "", ex); + this.mApkInstallTime = System.currentTimeMillis(); } - if(USE_MP3_COPY) { + if(ExampleProvider.USE_MP3_COPY) { // Extract our mp3s to storage as Poweramp won't properly play asset apk fd (fd points to apk itself, so Poweramp tries to play the apk file itself, // basically playing first found mp3 from it) - File dir = getContext().getFilesDir(); - copyAsset("bensound-dubstep.mp3", dir, false); - copyAsset("bensound-dubstep.flac", dir, false); - copyAsset("bensound-summer.mp3", dir, false); - copyAsset("streams-playlist.m3u8", dir, false); + final File dir = this.getContext().getFilesDir(); + this.copyAsset("bensound-dubstep.mp3", dir, false); + this.copyAsset("bensound-dubstep.flac", dir, false); + this.copyAsset("bensound-summer.mp3", dir, false); + this.copyAsset("streams-playlist.m3u8", dir, false); } return true; } @Override - public Cursor queryRoots(String[] projection) throws FileNotFoundException { - if(LOG) Log.w(TAG, "queryRoots projection=" + Arrays.toString(projection)); + public Cursor queryRoots(final String[] projection) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "queryRoots projection=" + Arrays.toString(projection)); try { - MatrixCursor c = new MatrixCursor(resolveRootProjection(projection)); + final MatrixCursor c = new MatrixCursor(ExampleProvider.resolveRootProjection(projection)); MatrixCursor.RowBuilder row; // Items without metadata provided by the provider (Poweramp reads track metadata from track itself) row = c.newRow(); - row.add(Root.COLUMN_ROOT_ID, "rootId1"); - row.add(Root.COLUMN_TITLE, "Root 1"); - row.add(Root.COLUMN_SUMMARY, "Poweramp Example Provider"); - row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD); // Required - row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher); - row.add(Root.COLUMN_DOCUMENT_ID, "root1"); + row.add(DocumentsContract.Root.COLUMN_ROOT_ID, "rootId1"); + row.add(DocumentsContract.Root.COLUMN_TITLE, "Root 1"); + row.add(DocumentsContract.Root.COLUMN_SUMMARY, "Poweramp Example Provider"); + row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD); // Required + row.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_launcher); + row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, "root1"); // Items with metadata (Poweramp gets metadata from cursor and doesn't try to read tags from tracks) row = c.newRow(); - row.add(Root.COLUMN_ROOT_ID, "rootId2"); - row.add(Root.COLUMN_TITLE, "Root 2"); - row.add(Root.COLUMN_SUMMARY, "Poweramp Example Provider"); - row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD); // Required - row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher); - row.add(Root.COLUMN_DOCUMENT_ID, "root2"); + row.add(DocumentsContract.Root.COLUMN_ROOT_ID, "rootId2"); + row.add(DocumentsContract.Root.COLUMN_TITLE, "Root 2"); + row.add(DocumentsContract.Root.COLUMN_SUMMARY, "Poweramp Example Provider"); + row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD); // Required + row.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_launcher); + row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, "root2"); // Streams: m3u8 playlist, http stream with the duration, http no-duration stream (radio) row = c.newRow(); - row.add(Root.COLUMN_ROOT_ID, "rootId3"); - row.add(Root.COLUMN_TITLE, "Root 3 (Streams)"); - row.add(Root.COLUMN_SUMMARY, "Poweramp Example Provider"); - row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD); // Required - row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher); - row.add(Root.COLUMN_DOCUMENT_ID, "root3"); + row.add(DocumentsContract.Root.COLUMN_ROOT_ID, "rootId3"); + row.add(DocumentsContract.Root.COLUMN_TITLE, "Root 3 (Streams)"); + row.add(DocumentsContract.Root.COLUMN_SUMMARY, "Poweramp Example Provider"); + row.add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD); // Required + row.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_launcher); + row.add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, "root3"); return c; - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "", th); } return null; } @@ -256,8 +254,8 @@ public Cursor queryRoots(String[] projection) throws FileNotFoundException { * - in this case Poweramp will ask for extra fields, such as lyrics/synced lyrics
*/ @Override - public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException { - if(LOG) Log.w(TAG, "queryDocument documentId=" + documentId + " projection=" + Arrays.toString(projection)); + public Cursor queryDocument(final String documentId, final String[] projection) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "queryDocument documentId=" + documentId + " projection=" + Arrays.toString(projection)); try { @@ -266,119 +264,119 @@ public Cursor queryDocument(String documentId, String[] projection) throws FileN // If this is root, just return static root data if(!documentId.contains("/") && documentId.startsWith("root")) { - final MatrixCursor c = new MatrixCursor(resolveDocumentProjection(projection)); - MatrixCursor.RowBuilder row = c.newRow(); - AssetManager assets = getContext().getResources().getAssets(); - fillFolderRow(documentId, row, hasSubDirs(assets, documentId) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveDocumentProjection(projection)); + final MatrixCursor.RowBuilder row = c.newRow(); + final AssetManager assets = this.getContext().getResources().getAssets(); + this.fillFolderRow(documentId, row, this.hasSubDirs(assets, documentId) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); // NOTE: we return display name derived from documentId here VS returning the same label as used for Root.COLUMN_TITLE // Real app should use same labels in both places (roots and queryDocument) for same root - row.add(Document.COLUMN_DISPLAY_NAME, capitalize(documentId)); + row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, this.capitalize(documentId)); return c; - } else if(documentId.startsWith("root3") && documentId.endsWith(DOCID_STATIC_URL_SUFFIX)) { + } else if(documentId.startsWith("root3") && documentId.endsWith(ExampleProvider.DOCID_STATIC_URL_SUFFIX)) { // Url mp3 with a duration. We must provide duration here to avoid endless/non-seekable stream - final MatrixCursor c = new MatrixCursor(resolveTrackProjection(projection)); - int trackNum = extractTrackNum(documentId); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveTrackProjection(projection)); + final int trackNum = ExampleProvider.extractTrackNum(documentId); if(documentId.contains("dubstep")) { - fillURLRow(documentId, c.newRow(), DUBSTEP_HTTP_URL, DUBSTEP_SIZE, "Dubstep", trackNum == 1 ? 0 : DUBSTEP_DURATION_MS, true, true, true); // Send wave + this.fillURLRow(documentId, c.newRow(), ExampleProvider.DUBSTEP_HTTP_URL, ExampleProvider.DUBSTEP_SIZE, "Dubstep", 1 == trackNum ? 0 : ExampleProvider.DUBSTEP_DURATION_MS, true, true, true); // Send wave } else { - boolean emptyWave = trackNum < 4; // 1..4 summer tracks with empty wave, for the others - allow Poweramp to scan them - fillURLRow(documentId, c.newRow(), SUMMER_HTTP_URL, SUMMER_SIZE, "Summer", trackNum == 1 ? 0 : SUMMER_DURATION_MS, true, false, emptyWave); + final boolean emptyWave = 4 > trackNum; // 1..4 summer tracks with empty wave, for the others - allow Poweramp to scan them + this.fillURLRow(documentId, c.newRow(), ExampleProvider.SUMMER_HTTP_URL, ExampleProvider.SUMMER_SIZE, "Summer", 1 == trackNum ? 0 : ExampleProvider.SUMMER_DURATION_MS, true, false, emptyWave); } return c; - } else if(documentId.startsWith("root3") && documentId.endsWith(DOCID_DYNAMIC_URL_SUFFIX)) { + } else if(documentId.startsWith("root3") && documentId.endsWith(ExampleProvider.DOCID_DYNAMIC_URL_SUFFIX)) { // Dynamic url to mp3 with a duration. We must provide duration here to avoid endless/non-seekable stream // NOTE: we use TrackProviderConsts.DYNAMIC_URL as URL here to indicate dynamic url track - final MatrixCursor c = new MatrixCursor(resolveTrackProjection(projection)); - int trackNum = extractTrackNum(documentId); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveTrackProjection(projection)); + final int trackNum = ExampleProvider.extractTrackNum(documentId); if(documentId.contains("dubstep")) { - fillURLRow(documentId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, DUBSTEP_SIZE, "Dubstep", DUBSTEP_DURATION_MS, true, true, true); // Send wave + this.fillURLRow(documentId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, ExampleProvider.DUBSTEP_SIZE, "Dubstep", ExampleProvider.DUBSTEP_DURATION_MS, true, true, true); // Send wave } else { - boolean emptyWave = trackNum < 4; // 1..4 summer tracks with empty wave, for the others - allow Poweramp to scan them - fillURLRow(documentId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, SUMMER_SIZE, "Summer", SUMMER_DURATION_MS, true, false, emptyWave); + final boolean emptyWave = 4 > trackNum; // 1..4 summer tracks with empty wave, for the others - allow Poweramp to scan them + this.fillURLRow(documentId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, ExampleProvider.SUMMER_SIZE, "Summer", ExampleProvider.SUMMER_DURATION_MS, true, false, emptyWave); } return c; } else if(documentId.endsWith(".mp3") || documentId.endsWith(".flac")) { // Seems like a track // We are adding metadata for root2 and check if it's actually requested as a small optimization (which can be big if track metadata retrieval requires additional processing) - boolean addMetadata = documentId.startsWith("root2/") && projection != null && arrayContains(projection, MediaStore.MediaColumns.TITLE); - final MatrixCursor c = new MatrixCursor(resolveTrackProjection(projection)); - - boolean addLyrics = projection != null - && (arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_LYRICS) - || arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_LYRICS_SYNCED)); - boolean sendWave = documentId.contains("dubstep") && projection != null - && arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_WAVE); - fillTrackRow( + final boolean addMetadata = documentId.startsWith("root2/") && null != projection && this.arrayContains(projection, MediaStore.MediaColumns.TITLE); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveTrackProjection(projection)); + + final boolean addLyrics = null != projection + && (this.arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_LYRICS) + || this.arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_LYRICS_SYNCED)); + final boolean sendWave = documentId.contains("dubstep") && null != projection + && this.arrayContains(projection, TrackProviderConsts.COLUMN_TRACK_WAVE); + this.fillTrackRow( documentId, c.newRow(), addMetadata, sendWave, // Adding wave as well to root2 tracks addLyrics, - extractTrackNum(documentId), + ExampleProvider.extractTrackNum(documentId), 0, TrackProviderConsts.FLAG_HAS_LYRICS // Set lyrics flag for all of these tracks ); return c; } else if(documentId.endsWith(".m3u")) { // Seems like a playlist - final MatrixCursor c = new MatrixCursor(resolveDocumentProjection(projection)); - fillPlaylistRow(documentId, c.newRow()); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveDocumentProjection(projection)); + this.fillPlaylistRow(documentId, c.newRow()); return c; } else { // This must be a directory - final MatrixCursor c = new MatrixCursor(resolveDocumentProjection(projection)); - AssetManager assets = getContext().getResources().getAssets(); - fillFolderRow(documentId, c.newRow(), hasSubDirs(assets, documentId) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveDocumentProjection(projection)); + final AssetManager assets = this.getContext().getResources().getAssets(); + this.fillFolderRow(documentId, c.newRow(), this.hasSubDirs(assets, documentId) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); return c; } - } catch(Throwable th) { - Log.e(TAG, "documentId=" + documentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); } return null; } - private void fillURLRow(@NonNull String documentId, @NonNull MatrixCursor.RowBuilder row, @NonNull String url, - long size, @NonNull String title, - long duration, boolean sendMetadata, boolean sendWave, boolean sendEmptyWave + private void fillURLRow(@NonNull final String documentId, @NonNull final MatrixCursor.RowBuilder row, @NonNull final String url, + final long size, @NonNull String title, + final long duration, final boolean sendMetadata, final boolean sendWave, final boolean sendEmptyWave ) { - row.add(Document.COLUMN_DOCUMENT_ID, documentId); - row.add(Document.COLUMN_MIME_TYPE, "audio/mpeg"); + row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, documentId); + row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, "audio/mpeg"); // The display name defines name of the track "file" in "Show File Names" mode. There is also a title via MediaStore.MediaColumns.TITLE. // It's up to you how you define display name, it can be anything filename alike, or it can just match track title - row.add(Document.COLUMN_DISPLAY_NAME, getShortName(documentId)); + row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, ExampleProvider.getShortName(documentId)); // As our assets data is always static, we just return own apk installation time. For real folder structure, preferable last modified for given folder should be returned. // This ensures Poweramp incremental scanning process. If we return <= 0 value here, Poweramp will be forced to rescan whole provider hierarchy each time it scans - row.add(Document.COLUMN_LAST_MODIFIED, mApkInstallTime); + row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, this.mApkInstallTime); // Optional, real provider should preferable return real track file size here or 0 - row.add(Document.COLUMN_SIZE, size); + row.add(DocumentsContract.Document.COLUMN_SIZE, size); // Setting this will cause Poweramp to ask for the track album art via getDocumentThumbnail, but only if other metadata (MediaStore.MediaColumns.TITLE/MediaStore.MediaColumns.DURATION) exists - row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_THUMBNAIL); + row.add(DocumentsContract.Document.COLUMN_FLAGS, DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL); row.add(TrackProviderConsts.COLUMN_URL, url); - row.add(MediaStore.Audio.AudioColumns.DURATION, duration); // Milliseconds, long. If duration <= 0, this is endless non-seekable stream (e.g. radio) + row.add(MediaStore.MediaColumns.DURATION, duration); // Milliseconds, long. If duration <= 0, this is endless non-seekable stream (e.g. radio) if(sendMetadata) { // NOTE: Poweramp doesn't need extra metadata (except COLUMN_URL/DURATION for streams) for queryDocuments, but requires that for queryDocument if(TrackProviderConsts.DYNAMIC_URL.equals(url)) { title += " Dynamic"; } - String prefix = title + " "; + final String prefix = title + " "; // Some dump tags logic - as we have 2 static files here as an example, but they have docId like dubstep1.mp3, summer2.mp3, etc. // Real provider should get this info from network or extract from the file - int trackNum = extractTrackNum(documentId); + final int trackNum = ExampleProvider.extractTrackNum(documentId); row.add(MediaStore.MediaColumns.TITLE, prefix + "URL Track " + trackNum); - row.add(MediaStore.Audio.AudioColumns.ARTIST, prefix + "URL Artist"); - row.add(MediaStore.Audio.AudioColumns.ALBUM, prefix + "URL Album"); + row.add(MediaStore.MediaColumns.ARTIST, prefix + "URL Artist"); + row.add(MediaStore.MediaColumns.ALBUM, prefix + "URL Album"); row.add(MediaStore.Audio.AudioColumns.YEAR, 2020); // Integer row.add(TrackProviderConsts.COLUMN_ALBUM_ARTIST, prefix + "URL Album Artist"); - row.add(MediaStore.Audio.AudioColumns.COMPOSER, prefix + "URL Composer"); + row.add(MediaStore.MediaColumns.COMPOSER, prefix + "URL Composer"); row.add(TrackProviderConsts.COLUMN_GENRE, prefix + "URL Genre"); // Track number. Optional, but needed for proper sorting in albums row.add(MediaStore.Audio.AudioColumns.TRACK, trackNum); @@ -390,8 +388,8 @@ private void fillURLRow(@NonNull String documentId, @NonNull MatrixCursor.RowBui row.add(MediaFormat.KEY_BIT_RATE, 128000); // Optional, used just for Info/Tags and lists (for hi-res) row.add(TrackProviderConsts.COLUMN_BITS_PER_SAMPLE, 16); - if(sendWave && duration > 0) { - row.add(TrackProviderConsts.COLUMN_TRACK_WAVE, TrackProviderHelper.floatsToBytes(genRandomWave())); // We must put byte[] array here + if(sendWave && 0 < duration) { + row.add(TrackProviderConsts.COLUMN_TRACK_WAVE, TrackProviderHelper.floatsToBytes(this.genRandomWave())); // We must put byte[] array here } else if(sendEmptyWave) { // Add this for the default waveseek if you don't want URL to be downloaded one more time and scanned for the wave row.add(TrackProviderConsts.COLUMN_TRACK_WAVE, new byte[0]); @@ -400,97 +398,97 @@ private void fillURLRow(@NonNull String documentId, @NonNull MatrixCursor.RowBui } private float[] genRandomWave() { - float[] wave = new float[100]; + final float[] wave = new float[100]; for(int i = 0; i < wave.length; i++) { wave[i] = (float)(Math.random() * 2.0 - 1.0); } return wave; } - private void fillFolderRow(@NonNull String documentId, @NonNull MatrixCursor.RowBuilder row, int flags) { - row.add(Document.COLUMN_DOCUMENT_ID, documentId); - row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); + private void fillFolderRow(@NonNull final String documentId, @NonNull final MatrixCursor.RowBuilder row, final int flags) { + row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, documentId); + row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR); // Here we're returning actual folder name, but Poweramp supports anything in display name for folders, not necessary the name matching or related to the documentId or path. - row.add(Document.COLUMN_DISPLAY_NAME, getShortDirName(documentId)); - row.add(Document.COLUMN_LAST_MODIFIED, mApkInstallTime); + row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, ExampleProvider.getShortDirName(documentId)); + row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, this.mApkInstallTime); - boolean hasThumb = documentId.endsWith("1"); + final boolean hasThumb = documentId.endsWith("1"); if(hasThumb) { - row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_THUMBNAIL); // Thumbnails for folders are supported since build 869 + row.add(DocumentsContract.Document.COLUMN_FLAGS, DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL); // Thumbnails for folders are supported since build 869 } // If asked to add the subfolders hint, add it - if(flags != 0) { + if(0 != flags) { row.add(TrackProviderConsts.COLUMN_FLAGS, flags); } } - private void fillPlaylistRow(@NonNull String documentId, @NonNull MatrixCursor.RowBuilder row) { + private void fillPlaylistRow(@NonNull final String documentId, @NonNull final MatrixCursor.RowBuilder row) { // NOTE: for playlists, the playlist documentId should preferable end with some extension. Poweramp also looks into mime type, or assumes it's .m3u8 playlist if no mime type - row.add(Document.COLUMN_DOCUMENT_ID, documentId); - row.add(Document.COLUMN_MIME_TYPE, "audio/mpegurl"); + row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, documentId); + row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, "audio/mpegurl"); // The display name defines name of the track "file" in "Show File Names" mode. There is also a title via MediaStore.MediaColumns.TITLE. // It's up to you how you define display name, it can be anything filename alike, or it can just match track title - row.add(Document.COLUMN_DISPLAY_NAME, getShortName(documentId)); + row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, ExampleProvider.getShortName(documentId)); // As our assets data is always static, we just return own apk installation time. For real folder structure, preferable last modified for given folder should be returned. // This ensures Poweramp incremental scanning process. If we return <= 0 value here, Poweramp will be forced to rescan whole provider hierarchy each time it scans - row.add(Document.COLUMN_LAST_MODIFIED, mApkInstallTime); + row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, this.mApkInstallTime); } private void fillTrackRow( - @NonNull String documentId, - @NonNull MatrixCursor.RowBuilder row, - boolean addMetadata, - boolean sendWave, - boolean sendLyrics, - int trackNum, - int trackNumAlt, - int extraFlags + @NonNull final String documentId, + @NonNull final MatrixCursor.RowBuilder row, + final boolean addMetadata, + final boolean sendWave, + final boolean sendLyrics, + final int trackNum, + final int trackNumAlt, + final int extraFlags ) { - boolean isFlac = documentId.endsWith(".flac"); - boolean isDubstep = documentId.contains("dubstep"); + final boolean isFlac = documentId.endsWith(".flac"); + final boolean isDubstep = documentId.contains("dubstep"); - row.add(Document.COLUMN_DOCUMENT_ID, documentId); - row.add(Document.COLUMN_MIME_TYPE, isFlac ? "audio/flac" : "audio/mpeg"); + row.add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, documentId); + row.add(DocumentsContract.Document.COLUMN_MIME_TYPE, isFlac ? "audio/flac" : "audio/mpeg"); // The display name defines name of the track "file" in "Show File Names" mode. There is also a title via MediaStore.MediaColumns.TITLE. // It's up to you how you define display name, it can be anything filename alike, or it can just match track title - row.add(Document.COLUMN_DISPLAY_NAME, getShortName(documentId)); + row.add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, ExampleProvider.getShortName(documentId)); // As our assets data is always static, we just return own apk installation time. For real folder structure, preferable last modified for given folder should be returned. // This ensures Poweramp incremental scanning process. If we return <= 0 value here, Poweramp will be forced to rescan whole provider hierarchy each time it scans - row.add(Document.COLUMN_LAST_MODIFIED, mApkInstallTime); + row.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, this.mApkInstallTime); - String filePath = docIdToFileName(documentId); // We only have 2 real mp3s here for many "virtual" tracks + final String filePath = this.docIdToFileName(documentId); // We only have 2 real mp3s here for many "virtual" tracks // Optional, real provider should preferable return real track file size here or 0. - row.add(Document.COLUMN_SIZE, getAssetFileSize(getContext().getResources().getAssets(), filePath)); + row.add(DocumentsContract.Document.COLUMN_SIZE, this.getAssetFileSize(this.getContext().getResources().getAssets(), filePath)); // NOTE: Poweramp doesn't need extra metadata (except COLUMN_URL/DURATION for streams) for queryDocuments, // but requires that for queryDocument for tracks, which are not direct fd. Direct fd tracks still can be quickly scanned by Poweramp, but // socket/pipe/url tracks won't be scanned and thus metadata is required for them // If provided, COLUMN_TRACK_ALT will sort tracks differently (for "by track #" sorting) in Folders/Folders Hierarchy - if(trackNumAlt > 0) { + if(0 < trackNumAlt) { row.add(TrackProviderConsts.COLUMN_TRACK_ALT, trackNumAlt); } if(addMetadata) { // Some dump tags logic - as we have 2 static files here as an example, but they have docId like dubstep1.mp3, summer2.mp3, etc. // Real provider should get this info from network or extract from the file - String prefix = isDubstep ? "Dubstep " : "Summer "; + final String prefix = isDubstep ? "Dubstep " : "Summer "; int flags = 0; // Setting this will cause Poweramp to ask for track album art via getDocumentThumbnail, but only if other metadata (MediaStore.MediaColumns.TITLE/MediaStore.MediaColumns.DURATION) exists - flags |= Document.FLAG_SUPPORTS_THUMBNAIL; + flags |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL; flags |= TrackProviderConsts.FLAG_HAS_LYRICS; - row.add(Document.COLUMN_FLAGS, flags); + row.add(DocumentsContract.Document.COLUMN_FLAGS, flags); row.add(MediaStore.MediaColumns.TITLE, prefix + "Track " + trackNum); - row.add(MediaStore.Audio.AudioColumns.ARTIST, prefix + "Artist"); - row.add(MediaStore.Audio.AudioColumns.DURATION, isDubstep ? 125000L : 217000L); // Milliseconds, long - row.add(MediaStore.Audio.AudioColumns.ALBUM, prefix + "Album"); + row.add(MediaStore.MediaColumns.ARTIST, prefix + "Artist"); + row.add(MediaStore.MediaColumns.DURATION, isDubstep ? 125000L : 217000L); // Milliseconds, long + row.add(MediaStore.MediaColumns.ALBUM, prefix + "Album"); row.add(MediaStore.Audio.AudioColumns.YEAR, isDubstep ? 2020 : 2019); // Integer row.add(TrackProviderConsts.COLUMN_ALBUM_ARTIST, prefix + "Album Artist"); - row.add(MediaStore.Audio.AudioColumns.COMPOSER, prefix + " Composer"); + row.add(MediaStore.MediaColumns.COMPOSER, prefix + " Composer"); row.add(TrackProviderConsts.COLUMN_GENRE, prefix + " Genre"); // Track number. Optional, but needed for proper sorting in albums. // If not defined (or set to <= 0), Poweramp will use cursor position for track - this may be useful for folders where we want default cursor based ordering of items - @@ -508,11 +506,11 @@ private void fillTrackRow( row.add(TrackProviderConsts.COLUMN_BITS_PER_SAMPLE, 16); if(sendWave) { - row.add(TrackProviderConsts.COLUMN_TRACK_WAVE, TrackProviderHelper.floatsToBytes(genRandomWave())); + row.add(TrackProviderConsts.COLUMN_TRACK_WAVE, TrackProviderHelper.floatsToBytes(this.genRandomWave())); } // Add our own extra flags if any - if(extraFlags != 0) { + if(0 != extraFlags) { row.add(TrackProviderConsts.COLUMN_FLAGS, extraFlags); } @@ -538,36 +536,36 @@ private void fillTrackRow( * based on track # or other user selected criteria. Instead, we use sortOrder as optional additional parameter for things like */ @Override - public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { - if(LOG) Log.w(TAG, "queryChildDocuments parentDocumentId=" + parentDocumentId + " projection=" + Arrays.toString(projection)); + public Cursor queryChildDocuments(final String parentDocumentId, final String[] projection, final String sortOrder) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "queryChildDocuments parentDocumentId=" + parentDocumentId + " projection=" + Arrays.toString(projection)); try { - AssetManager assets = getContext().getResources().getAssets(); - String[] filesAndDirs = assets.list(parentDocumentId); + final AssetManager assets = this.getContext().getResources().getAssets(); + final String[] filesAndDirs = assets.list(parentDocumentId); // To demonstrate folders and files sorting based on cursor position, sort and reverse the array. Do this for Root1 - if(parentDocumentId.equals("root1")) { + if("root1".equals(parentDocumentId)) { Arrays.sort(filesAndDirs, 0, filesAndDirs.length, new Comparator() { @Override - public int compare(String o1, String o2) { + public int compare(final String o1, final String o2) { return o2.compareToIgnoreCase(o1); } }); } // We are adding metadata for root2 and check if it's actually requested as a small optimization (which can be big if track metadata retrieval requires additional processing) - boolean addMetadata = parentDocumentId.startsWith("root2") && projection != null && arrayContains(projection, MediaStore.MediaColumns.TITLE); + final boolean addMetadata = parentDocumentId.startsWith("root2") && null != projection && this.arrayContains(projection, MediaStore.MediaColumns.TITLE); - if(LOG) Log.w(TAG, "queryChildDocuments filesAndDirs=" + Arrays.toString(filesAndDirs)); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "queryChildDocuments filesAndDirs=" + Arrays.toString(filesAndDirs)); - final MatrixCursor c = new MatrixCursor(resolveDocumentProjection(projection)); + MatrixCursor c = new MatrixCursor(ExampleProvider.resolveDocumentProjection(projection)); - int ix = 0; - for(String fileOrDir : filesAndDirs) { - String path = parentDocumentId + "/" + fileOrDir; // Path is our documentId. Note that this provider defines paths/documentIds format. Poweramp treats them as opaque string + final int ix = 0; + for(final String fileOrDir : filesAndDirs) { + final String path = parentDocumentId + "/" + fileOrDir; // Path is our documentId. Note that this provider defines paths/documentIds format. Poweramp treats them as opaque string - if(isAssetDir(assets, path)) { - fillFolderRow(path, c.newRow(), hasSubDirs(assets, path) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); + if(this.isAssetDir(assets, path)) { + this.fillFolderRow(path, c.newRow(), this.hasSubDirs(assets, path) ? TrackProviderConsts.FLAG_HAS_SUBDIRS : TrackProviderConsts.FLAG_NO_SUBDIRS); } // Else this is empty.txt file, we skip it } @@ -578,41 +576,41 @@ public int compare(String o1, String o2) { // - parent folder lastModified changed // - full rescan required by user or external intent - int count = parentDocumentId.length(); // Just various number based on parent document path length + final int count = parentDocumentId.length(); // Just various number based on parent document path length String docId; - if(parentDocumentId.equals("root3")) { + if("root3".equals(parentDocumentId)) { // For root3 add m3u8 playlist - fillPlaylistRow(parentDocumentId + "/" + "streams-playlist.m3u8", c.newRow()); + this.fillPlaylistRow(parentDocumentId + "/" + "streams-playlist.m3u8", c.newRow()); // Add dynamic URL tracks - docId = parentDocumentId + "/" + "dubstep" + "-" + 1 + DOCID_DYNAMIC_URL_SUFFIX; - fillURLRow(docId, c.newRow(), + docId = parentDocumentId + "/" + "dubstep" + "-" + 1 + ExampleProvider.DOCID_DYNAMIC_URL_SUFFIX; + this.fillURLRow(docId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, - DUBSTEP_SIZE, + ExampleProvider.DUBSTEP_SIZE, "", // NOTE: titles not sent here - DUBSTEP_DURATION_MS, + ExampleProvider.DUBSTEP_DURATION_MS, false, false, false); // Not sending metadata here - docId = parentDocumentId + "/" + "summer" + "-" + 2 + DOCID_DYNAMIC_URL_SUFFIX; - fillURLRow(docId, c.newRow(), + docId = parentDocumentId + "/" + "summer" + "-" + 2 + ExampleProvider.DOCID_DYNAMIC_URL_SUFFIX; + this.fillURLRow(docId, c.newRow(), TrackProviderConsts.DYNAMIC_URL, - SUMMER_SIZE, + ExampleProvider.SUMMER_SIZE, "", // NOTE: titles not sent here - SUMMER_DURATION_MS, + ExampleProvider.SUMMER_DURATION_MS, false, false, false); // Not sending metadata here // And fill with random number of http links to the tracks for(int i = 0; i < count; i++) { - boolean isDubstep = (i & 1) != 0; - boolean isStream = i == 0; // First track here will be a "stream" - non seekable, no duration - docId = parentDocumentId + "/" + (isDubstep ? "dubstep" : "summer") + "-" + (i + 3) + DOCID_STATIC_URL_SUFFIX; - fillURLRow(docId, c.newRow(), - isDubstep ? DUBSTEP_HTTP_URL : SUMMER_HTTP_URL, - isDubstep ? DUBSTEP_SIZE : SUMMER_SIZE, + final boolean isDubstep = 0 != (i & 1); + final boolean isStream = 0 == i; // First track here will be a "stream" - non seekable, no duration + docId = parentDocumentId + "/" + (isDubstep ? "dubstep" : "summer") + "-" + (i + 3) + ExampleProvider.DOCID_STATIC_URL_SUFFIX; + this.fillURLRow(docId, c.newRow(), + isDubstep ? ExampleProvider.DUBSTEP_HTTP_URL : ExampleProvider.SUMMER_HTTP_URL, + isDubstep ? ExampleProvider.DUBSTEP_SIZE : ExampleProvider.SUMMER_SIZE, "", // NOTE: titles not sent here - isStream ? 0 : (isDubstep ? DUBSTEP_DURATION_MS : SUMMER_DURATION_MS), + isStream ? 0 : (isDubstep ? ExampleProvider.DUBSTEP_DURATION_MS : ExampleProvider.SUMMER_DURATION_MS), false, false, false); } @@ -622,19 +620,19 @@ public int compare(String o1, String o2) { // For root1, demonstrate Folders/Folders Hierarchy sorting based on alternative track number // We reverse number positions of tracks here, but still providing non-reversed track number to use as tag number in albums and other non-folder categories for(int i = 0; i < count; i++) { - docId = parentDocumentId + "/" + ((i & 1) != 0 ? "dubstep" : "summer") + "-" + (i + 1) + (i == 1 ? ".flac" : ".mp3"); // First dubstep track will be flac - int sort = i + 1; + docId = parentDocumentId + "/" + (0 != (i & 1) ? "dubstep" : "summer") + "-" + (i + 1) + (1 == i ? ".flac" : ".mp3"); // First dubstep track will be flac + final int sort = i + 1; int sortAlt = 0; - if(parentDocumentId.equals("root1")) { + if("root1".equals(parentDocumentId)) { sortAlt = count - i; } - fillTrackRow(docId, c.newRow(), addMetadata, false, false, sort, sortAlt, 0); + this.fillTrackRow(docId, c.newRow(), addMetadata, false, false, sort, sortAlt, 0); } } return c; - } catch(Throwable th) { - Log.e(TAG, "documentId=" + parentDocumentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + parentDocumentId, th); } return null; @@ -643,33 +641,33 @@ public int compare(String o1, String o2) { /** * Simple method to check our assets directory structure for children folders. We have only folders and empty.txt files there */ - private boolean hasSubDirs(AssetManager assets, String path) { + private boolean hasSubDirs(final AssetManager assets, final String path) { try { - String[] filesAndDirs = assets.list(path); - if(filesAndDirs != null && filesAndDirs.length > 0) { - for(String child : filesAndDirs) { + final String[] filesAndDirs = assets.list(path); + if(null != filesAndDirs && 0 < filesAndDirs.length) { + for(final String child : filesAndDirs) { if(!child.endsWith(".txt")) { return true; } } } - } catch(IOException e) { - Log.e(TAG, path, e); + } catch(final IOException e) { + Log.e(ExampleProvider.TAG, path, e); } return false; } /** Send album art for tracks with track-provided metadata */ @Override - public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException { + public AssetFileDescriptor openDocumentThumbnail(final String documentId, final Point sizeHint, final CancellationSignal signal) throws FileNotFoundException { - String imageSrc; + final String imageSrc; - if(documentId.endsWith(".mp3") || documentId.endsWith(".flac") || documentId.endsWith(DOCID_STATIC_URL_SUFFIX) - || documentId.endsWith(DOCID_DYNAMIC_URL_SUFFIX) + if(documentId.endsWith(".mp3") || documentId.endsWith(".flac") || documentId.endsWith(ExampleProvider.DOCID_STATIC_URL_SUFFIX) + || documentId.endsWith(ExampleProvider.DOCID_DYNAMIC_URL_SUFFIX) ) { // We have just 2 images here and we ignore sizeHint. Poweramp preferred image size is 1024x1024px - boolean isDubstep = documentId.contains("dubstep"); + final boolean isDubstep = documentId.contains("dubstep"); imageSrc = isDubstep ? "cover-1.jpg" : "cover-2.jpg"; } else { @@ -677,14 +675,14 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHi imageSrc = "folder-1.jpg"; } - if(LOG) Log.w(TAG, "openDocumentThumbnail documentId=" + documentId + " sizeHint=" + sizeHint + " imageSrc=" + imageSrc); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openDocumentThumbnail documentId=" + documentId + " sizeHint=" + sizeHint + " imageSrc=" + imageSrc); - if(imageSrc == null) throw new FileNotFoundException(documentId); + if(null == imageSrc) throw new FileNotFoundException(documentId); try { - return getContext().getResources().getAssets().openFd(imageSrc); - } catch(IOException e) { + return this.getContext().getResources().getAssets().openFd(imageSrc); + } catch(final IOException e) { throw new FileNotFoundException(documentId); } } @@ -693,48 +691,49 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHi * Send actual track data as direct file descriptor or seekable socket protocol */ @Override - public ParcelFileDescriptor openDocument(String documentId, String mode, CancellationSignal signal) throws FileNotFoundException { - if(LOG) Log.w(TAG, "openDocument documentId=" + documentId + " mode=" + mode + " callingPak=" + getCallingPackage()); - int accessMode = ParcelFileDescriptor.parseMode(mode); - if((accessMode & ParcelFileDescriptor.MODE_READ_ONLY) == 0) throw new IllegalAccessError("documentId=" + documentId + " mode=" + mode); + public ParcelFileDescriptor openDocument(final String documentId, final String mode, final CancellationSignal signal) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openDocument documentId=" + documentId + " mode=" + mode + " callingPak=" + this.getCallingPackage()); + final int accessMode = ParcelFileDescriptor.parseMode(mode); + if(0 == (accessMode & ParcelFileDescriptor.MODE_READ_ONLY)) throw new IllegalAccessError("documentId=" + documentId + " mode=" + mode); // Poweramp provides CancellationSignal, so we may want to check that on open and periodically (for example, in case of using pipe here) - if(signal != null) { + if(null != signal) { signal.throwIfCanceled(); } - String filePath = docIdToFileName(documentId); - if(filePath == null) throw new FileNotFoundException(documentId); + final String filePath = this.docIdToFileName(documentId); + if(null == filePath) throw new FileNotFoundException(documentId); // Let's send root2 "dubstep" via seekable socket and other files - via direct fd. Don't do this for root1 where no metadata given and Poweramp expects direct fd tracks // Check package name for Poweramp (or other known client) which supports this fd protocol - String pak = getCallingPackage(); - if(pak != null && pak.equals(PowerampAPIHelper.getPowerampPackageName(getContext())) + final String pak = this.getCallingPackage(); + if(null != pak && pak.equals(PowerampAPIHelper.getPowerampPackageName(this.getContext())) && documentId.startsWith("root2/") && documentId.contains("dubstep") ) { // Let's open dubstep-2 via milliseconds based seekbable sockets, and other dubsteps - via byte offset seekable sockets if(documentId.endsWith("-2.flac")) { - return openViaSeekableSocket2(documentId, filePath, signal); + return this.openViaSeekableSocket2(documentId, filePath, signal); } else { - return openViaSeekableSocket(documentId, filePath, signal); + return this.openViaSeekableSocket(documentId, filePath, signal); } } // Let's send root2 "summer" via seekable proxy file descriptors. No need to check for client package as these file descriptors should be supported everywhere - if(Build.VERSION.SDK_INT >= 26 && USE_OPEN_PROXY_FILE_DESCRIPTOR && documentId.startsWith("root2/") && documentId.contains("summer")) { - return openViaProxyFd(documentId, filePath, signal); + if(26 <= Build.VERSION.SDK_INT && ExampleProvider.USE_OPEN_PROXY_FILE_DESCRIPTOR && documentId.startsWith("root2/") && documentId.contains("summer")) { + return this.openViaProxyFd(documentId, filePath, signal); } - return openViaDirectFD(documentId, filePath); + return this.openViaDirectFD(documentId, filePath); } /** For given docId, return appropriate asset file name */ - private @Nullable String docIdToFileName(String documentId) { + @Nullable + private String docIdToFileName(final String documentId) { if(documentId.endsWith(".m3u8")) { return "streams-playlist.m3u8"; } else if(documentId.endsWith(".mp3")) { - boolean isDubstep = documentId.contains("dubstep"); + final boolean isDubstep = documentId.contains("dubstep"); return isDubstep ? "bensound-dubstep.mp3" : "bensound-summer.mp3"; // We only have 2 real mp3s here for many "virtual" tracks } else if(documentId.endsWith(".flac")) { @@ -745,29 +744,29 @@ public ParcelFileDescriptor openDocument(String documentId, String mode, Cancell } /** This version of the method uses byte offset based seeks */ - private ParcelFileDescriptor openViaSeekableSocket(final String documentId, String filePath, final CancellationSignal signal) throws FileNotFoundException { - if(LOG) Log.w(TAG, "openViaSeekableSocket documentId=" + documentId + " filePath=" + filePath); + private ParcelFileDescriptor openViaSeekableSocket(String documentId, final String filePath, CancellationSignal signal) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket documentId=" + documentId + " filePath=" + filePath); try { - final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); - final File file = new File(getContext().getFilesDir(), filePath); - final long fileLength = file.length(); + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); + File file = new File(this.getContext().getFilesDir(), filePath); + long fileLength = file.length(); - if(DEBUG_ALWAYS_STOP_IN_OPEN) { - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_IN_OPEN"); + if(ExampleProvider.DEBUG_ALWAYS_STOP_IN_OPEN) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_IN_OPEN"); // NOTE: in this case if we just return socket here and stop, Poweramp will still wait for timeout // as socket was never closed from our side // If we want fail-fast approach from Poweramp, either return null here, or shutdown socket properly new Thread(new Runnable() { public void run() { - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP shutdown socket"); - FileDescriptor socket = fds[1].getFileDescriptor(); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP shutdown socket"); + final FileDescriptor socket = fds[1].getFileDescriptor(); try { Os.shutdown(socket, 0); - } catch(ErrnoException ex) { + } catch(final ErrnoException ex) { } try { Os.close(socket); - } catch(ErrnoException ex) { + } catch(final ErrnoException ex) { } } }).start(); @@ -782,46 +781,46 @@ public void run() { public void run() { // NOTE: we can use arbitrary buffer size here >0, but increasing buffer will increase non-seekable "window" at the end of file // Using buffer size > MAX_DATA_SIZE will cause buffer to be split into multiple packets - ByteBuffer buf = ByteBuffer.allocateDirect(TrackProviderProto.MAX_DATA_SIZE); + final ByteBuffer buf = ByteBuffer.allocateDirect(TrackProviderProto.MAX_DATA_SIZE); buf.order(ByteOrder.nativeOrder()); long bytesSent = 0; - try(FileInputStream fis = new FileInputStream(file)) { - FileChannel fc = fis.getChannel(); // We'll be using nio for the buffer loading - try(TrackProviderProto proto = new TrackProviderProto(fds[1], fileLength)) { + try(final FileInputStream fis = new FileInputStream(file)) { + final FileChannel fc = fis.getChannel(); // We'll be using nio for the buffer loading + try(final TrackProviderProto proto = new TrackProviderProto(fds[1], fileLength)) { - if(DEBUG_ALWAYS_STOP_PROTOCOL) { - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_PROTOCOL"); + if(ExampleProvider.DEBUG_ALWAYS_STOP_PROTOCOL) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_PROTOCOL"); return; // Immediately stop. NOTE: this will call proto.close automatically } proto.sendHeader(); // Send initial header - if(DEBUG_STOP_PROTOCOL_AFTER_HEADER) { - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP due to DEBUG_STOP_PROTOCOL_AFTER_HEADER"); + if(ExampleProvider.DEBUG_STOP_PROTOCOL_AFTER_HEADER) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP due to DEBUG_STOP_PROTOCOL_AFTER_HEADER"); return; // Immediately stop. NOTE: this will call proto.close automatically } while(true) { int len; //noinspection UnusedAssignment - while((len = fc.read(buf)) > 0) { + while(0 < (len = fc.read(buf))) { buf.flip(); // Send some data to Poweramp and optionally receive seek request // NOTE: avoid sending empty buffers here (!buf.hasRemaining()), as this will cause premature EOF - long seekRequestPos = proto.sendData(buf); + final long seekRequestPos = proto.sendData(buf); - handleSeekRequest(proto, seekRequestPos, fc, fileLength); // May be handle seek request + ExampleProvider.this.handleSeekRequest(proto, seekRequestPos, fc, fileLength); // May be handle seek request bytesSent += buf.limit(); buf.clear(); - if(DEBUG_STOP_PROTOCOL_AFTER_BYTES > 0 && bytesSent >= DEBUG_STOP_PROTOCOL_AFTER_BYTES) { + if(ExampleProvider.DEBUG_STOP_PROTOCOL_AFTER_BYTES > 0 && DEBUG_STOP_PROTOCOL_AFTER_BYTES <= bytesSent) { // Force-stop playback from our side - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP due to DEBUG_STOP_AFTER_BYTES"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP due to DEBUG_STOP_AFTER_BYTES"); return; } } @@ -836,9 +835,9 @@ public void run() { // Solution to this is to keep file and socket opened here and to continue seek commands processing until Poweramp actually closes socket. // This scenario can be easily tested by pausing Poweramp close to the track end and seeking while paused - long seekRequestPos = proto.sendEOFAndWaitForSeekOrClose(); - if(handleSeekRequest(proto, seekRequestPos, fc, fileLength)) { - if(LOG) Log.w(TAG, "openViaSeekableSocket file seek past EOF documentId=" + documentId); + final long seekRequestPos = proto.sendEOFAndWaitForSeekOrClose(); + if(ExampleProvider.this.handleSeekRequest(proto, seekRequestPos, fc, fileLength)) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket file seek past EOF documentId=" + documentId); //noinspection UnnecessaryContinue continue; // We've just processed extra seek request, continue sending buffers } else { @@ -846,34 +845,34 @@ public void run() { } } - if(LOG) Log.w(TAG, " openViaSeekableSocket file DONE documentId=" + documentId); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, " openViaSeekableSocket file DONE documentId=" + documentId); } - } catch(TrackProviderProto.TrackProviderProtoClosed ex) { - if(LOG) Log.w(TAG, "openViaSeekableSocket closed documentId=" + documentId + " " + ex.getMessage()); - } catch(Throwable th) { + } catch(final TrackProviderProto.TrackProviderProtoClosed ex) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket closed documentId=" + documentId + " " + ex.getMessage()); + } catch(final Throwable th) { // If we're here, we can't do much - close connection, release resources, and exit - Log.e(TAG, "documentId=" + documentId, th); + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); } } }).start(); return fds[0]; - } catch(Throwable th) { - Log.e(TAG, "documentId=" + documentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); throw new FileNotFoundException(documentId); } } /** This version of the method uses milliseconds offset based seek requests */ - private ParcelFileDescriptor openViaSeekableSocket2(final String documentId, String filePath, final CancellationSignal signal) throws FileNotFoundException { - if(LOG) Log.w(TAG, "openViaSeekableSocket2 documentId=" + documentId + " filePath=" + filePath); + private ParcelFileDescriptor openViaSeekableSocket2(String documentId, final String filePath, CancellationSignal signal) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 documentId=" + documentId + " filePath=" + filePath); try { - final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); - final File file = new File(getContext().getFilesDir(), filePath); + ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); + File file = new File(this.getContext().getFilesDir(), filePath); - if(DEBUG_ALWAYS_STOP_IN_OPEN) { - if(LOG) Log.w(TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_IN_OPEN - return null"); + if(ExampleProvider.DEBUG_ALWAYS_STOP_IN_OPEN) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket STOP due to DEBUG_ALWAYS_STOP_IN_OPEN - return null"); // NOTE: in this case if we just return socket here and stop, Poweramp will still wait for timeout // as socket was never closed from our side // If we want fail-fast approach from Poweramp, either return null here, or shutdown socket properly @@ -885,7 +884,7 @@ private ParcelFileDescriptor openViaSeekableSocket2(final String documentId, Str // NOTE: for the sake of testing, let's send some approximation of the file instead, based on // duration and average bytes per ms // The real DUBSTEP_AVERAGE_BYTES_PER_MS depends on compression and file format - final long fileLength = DUBSTEP_FAKE_AVERAGE_BYTES_PER_MS * DUBSTEP_DURATION_MS; + long fileLength = ExampleProvider.DUBSTEP_FAKE_AVERAGE_BYTES_PER_MS * ExampleProvider.DUBSTEP_DURATION_MS; // NOTE: it's not possible to use timeouts on this side of the socket as Poweramp may open and hold the socket for an indefinite time while in the paused state // NOTE: don't use AsyncTask or other short-time thread pools here, as: @@ -896,44 +895,44 @@ private ParcelFileDescriptor openViaSeekableSocket2(final String documentId, Str @SuppressWarnings("UnusedAssignment") public void run() { // NOTE: we can use arbitrary buffer size here >0, but increasing buffer will increase non-seekable "window" at the end of file // Using buffer size > MAX_DATA_SIZE will cause buffer to be split into multiple packets - ByteBuffer buf = ByteBuffer.allocateDirect(TrackProviderProto.MAX_DATA_SIZE); + final ByteBuffer buf = ByteBuffer.allocateDirect(TrackProviderProto.MAX_DATA_SIZE); buf.order(ByteOrder.nativeOrder()); long bytesSent = 0; - try(FileInputStream fis = new FileInputStream(file)) { - FileChannel fc = fis.getChannel(); // We'll be using nio for the buffer loading - try(TrackProviderProto proto = new TrackProviderProto(fds[1], fileLength)) { + try(final FileInputStream fis = new FileInputStream(file)) { + final FileChannel fc = fis.getChannel(); // We'll be using nio for the buffer loading + try(final TrackProviderProto proto = new TrackProviderProto(fds[1], fileLength)) { - if(DEBUG_ALWAYS_STOP_PROTOCOL) { - if(LOG) Log.w(TAG, "openViaSeekableSocket2 STOP due to DEBUG_ALWAYS_STOP_PROTOCOL"); + if(ExampleProvider.DEBUG_ALWAYS_STOP_PROTOCOL) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 STOP due to DEBUG_ALWAYS_STOP_PROTOCOL"); return; // Immediately stop. NOTE: this will call proto.close automatically } proto.sendHeader(); // Send initial header - if(DEBUG_STOP_PROTOCOL_AFTER_HEADER) { - if(LOG) Log.w(TAG, "openViaSeekableSocket2 STOP due to DEBUG_STOP_PROTOCOL_AFTER_HEADER"); + if(ExampleProvider.DEBUG_STOP_PROTOCOL_AFTER_HEADER) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 STOP due to DEBUG_STOP_PROTOCOL_AFTER_HEADER"); return; // Immediately stop. NOTE: this will call proto.close automatically } while(true) { int len; - while((len = fc.read(buf)) > 0) { + while(0 < (len = fc.read(buf))) { buf.flip(); // Send some data to Poweramp and optionally receive seek request // NOTE: avoid sending empty buffers here (!buf.hasRemaining()), as this will cause premature EOF - TrackProviderProto.SeekRequest seekRequest = proto.sendData2(buf); + final TrackProviderProto.SeekRequest seekRequest = proto.sendData2(buf); - handleSeekRequest2(proto, seekRequest, fc, fileLength); // May be handle seek request + ExampleProvider.this.handleSeekRequest2(proto, seekRequest, fc, fileLength); // May be handle seek request bytesSent += buf.limit(); buf.clear(); - if(DEBUG_STOP_PROTOCOL_AFTER_BYTES > 0 && bytesSent >= DEBUG_STOP_PROTOCOL_AFTER_BYTES) { + if(ExampleProvider.DEBUG_STOP_PROTOCOL_AFTER_BYTES > 0 && DEBUG_STOP_PROTOCOL_AFTER_BYTES <= bytesSent) { // Force-stop playback from our side - if(LOG) Log.w(TAG, "openViaSeekableSocket2 STOP due to DEBUG_STOP_AFTER_BYTES"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 STOP due to DEBUG_STOP_AFTER_BYTES"); return; } } @@ -948,9 +947,9 @@ private ParcelFileDescriptor openViaSeekableSocket2(final String documentId, Str // Solution to this is to keep file and socket opened here and to continue seek commands processing until Poweramp actually closes socket. // This scenario can be easily tested by pausing Poweramp close to the track end and seeking while paused - TrackProviderProto.SeekRequest seekRequest = proto.sendEOFAndWaitForSeekOrClose2(); - if(handleSeekRequest2(proto, seekRequest, fc, fileLength)) { - if(LOG) Log.w(TAG, "openViaSeekableSocket2 file seek past EOF documentId=" + documentId); + final TrackProviderProto.SeekRequest seekRequest = proto.sendEOFAndWaitForSeekOrClose2(); + if(ExampleProvider.this.handleSeekRequest2(proto, seekRequest, fc, fileLength)) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 file seek past EOF documentId=" + documentId); //noinspection UnnecessaryContinue continue; // We've just processed extra seek request, continue sending buffers } else { @@ -958,86 +957,86 @@ private ParcelFileDescriptor openViaSeekableSocket2(final String documentId, Str } } - if(LOG) Log.w(TAG, " openViaSeekableSocket2 file DONE documentId=" + documentId); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, " openViaSeekableSocket2 file DONE documentId=" + documentId); } - } catch(TrackProviderProto.TrackProviderProtoClosed ex) { - if(LOG) Log.w(TAG, "openViaSeekableSocket2 closed documentId=" + documentId + " " + ex.getMessage()); - } catch(Throwable th) { + } catch(final TrackProviderProto.TrackProviderProtoClosed ex) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaSeekableSocket2 closed documentId=" + documentId + " " + ex.getMessage()); + } catch(final Throwable th) { // If we're here, we can't do much - close connection, release resources, and exit - Log.e(TAG, "documentId=" + documentId, th); + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); } } }).start(); return fds[0]; - } catch(Throwable th) { - Log.e(TAG, "documentId=" + documentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); throw new FileNotFoundException(documentId); } } @RequiresApi(api = Build.VERSION_CODES.O) - private ParcelFileDescriptor openViaProxyFd(final String documentId, final String filePath, final CancellationSignal signal) throws FileNotFoundException { - if(LOG) Log.w(TAG, "openViaProxyFd documentId=" + documentId + " filePath=" + filePath); + private ParcelFileDescriptor openViaProxyFd(String documentId, String filePath, CancellationSignal signal) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaProxyFd documentId=" + documentId + " filePath=" + filePath); FileInputStream fis = null; try { - final File file = new File(getContext().getFilesDir(), filePath); - final long fileLength = file.length(); + File file = new File(this.getContext().getFilesDir(), filePath); + long fileLength = file.length(); fis = new FileInputStream(file); - final FileDescriptor fd = fis.getFD(); + FileDescriptor fd = fis.getFD(); - final HandlerThread thread = new HandlerThread(documentId); // This is the thread we're handling fd reading on + HandlerThread thread = new HandlerThread(documentId); // This is the thread we're handling fd reading on thread.start(); - Handler handler = new Handler(thread.getLooper()); + final Handler handler = new Handler(thread.getLooper()); - StorageManager storageManager = (StorageManager)getContext().getSystemService(Context.STORAGE_SERVICE); + final StorageManager storageManager = (StorageManager) this.getContext().getSystemService(Context.STORAGE_SERVICE); - final FileInputStream finalFis = fis; + FileInputStream finalFis = fis; - ParcelFileDescriptor pfd = storageManager.openProxyFileDescriptor(ParcelFileDescriptor.MODE_READ_ONLY, new ProxyFileDescriptorCallback() { + final ParcelFileDescriptor pfd = storageManager.openProxyFileDescriptor(ParcelFileDescriptor.MODE_READ_ONLY, new ProxyFileDescriptorCallback() { @Override public long onGetSize() throws ErrnoException { - if(LOG) Log.w(TAG, "onGetSize fileLength=" + fileLength + " documentId=" + documentId); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "onGetSize fileLength=" + fileLength + " documentId=" + documentId); return fileLength; } - public int onRead(long offset, int size, byte[] data) throws ErrnoException { + public int onRead(final long offset, final int size, final byte[] data) throws ErrnoException { try { // NOTE: doing direct low level reads on file descriptor // Real provider, for example, for http streaming, could track offset and request remote seek if needed, // then read data from http stream to byte[] data - if(LOG) Log.w(TAG, "onRead documentId=" + documentId + " offset=" + offset + " size=" + size + " thread=" + Thread.currentThread()); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "onRead documentId=" + documentId + " offset=" + offset + " size=" + size + " thread=" + Thread.currentThread()); return Os.pread(fd, data, 0, size, offset); - } catch(ErrnoException errno) { - Log.e(TAG, "documentId=" + documentId + " filePath=" + filePath, errno); + } catch(final ErrnoException errno) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId + " filePath=" + filePath, errno); throw errno; // Rethrow - } catch(Throwable e) { - Log.e(TAG, "documentId=" + documentId + " filePath=" + filePath, e); + } catch(final Throwable e) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId + " filePath=" + filePath, e); throw new ErrnoException("onRead", OsConstants.EBADF); } } @Override public void onRelease() { - if(LOG) Log.w(TAG, "openViaProxyFd onRelease"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaProxyFd onRelease"); thread.quitSafely(); - closeSilently(finalFis); + ExampleProvider.closeSilently(finalFis); - if(LOG) Log.w(TAG, "openViaProxyFd DONE"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaProxyFd DONE"); } }, handler); return pfd; - } catch(Throwable th) { - Log.e(TAG, "documentId=" + documentId, th); - closeSilently(fis); // If we here, we failed with or prior the proxy, so close everything + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); + ExampleProvider.closeSilently(fis); // If we here, we failed with or prior the proxy, so close everything throw new FileNotFoundException(documentId); } } @@ -1046,17 +1045,17 @@ public void onRelease() { * THREADING: worker thread * @return true if we actually handled seek request, false otherwise */ - private boolean handleSeekRequest(@NonNull TrackProviderProto proto, long seekRequestPos, @NonNull FileChannel fc, long fileLength) { - if(seekRequestPos != TrackProviderProto.INVALID_SEEK_POS) { + private boolean handleSeekRequest(@NonNull final TrackProviderProto proto, final long seekRequestPos, @NonNull final FileChannel fc, final long fileLength) { + if(TrackProviderProto.INVALID_SEEK_POS != seekRequestPos) { // We have a seek request. // Your code may take any reasonable time to fulfil the seek request, e.g. it can reopen http connection with appropriate offset, etc. // Poweramp just waits for the seek result packet (the waiting is limited by the user-set timeout). // Now we should either send appropriate seek result packet or close the connection (e.g. on some error). // Poweramp ignores any other packets sent before the seek result packet. - if(LOG) Log.w(TAG, "handleSeekRequest seekRequestPos=" + seekRequestPos + " fileLength=" + fileLength); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleSeekRequest seekRequestPos=" + seekRequestPos + " fileLength=" + fileLength); - long newPos = seekTrack(fc, seekRequestPos, fileLength); + final long newPos = this.seekTrack(fc, seekRequestPos, fileLength); proto.sendSeekResult(newPos); return true; } @@ -1069,17 +1068,17 @@ private boolean handleSeekRequest(@NonNull TrackProviderProto proto, long seekRe * Still, we need to send some byte based newPos offset back to Poweramp. The resulting byte offset may be an approximation * @return true if we actually handled seek request, false otherwise */ - private boolean handleSeekRequest2(@NonNull TrackProviderProto proto, @Nullable TrackProviderProto.SeekRequest seekRequest, - @NonNull FileChannel fc, long fileLength + private boolean handleSeekRequest2(@NonNull final TrackProviderProto proto, @Nullable final TrackProviderProto.SeekRequest seekRequest, + @NonNull final FileChannel fc, final long fileLength ) { - if(seekRequest != null && seekRequest.offsetBytes != TrackProviderProto.INVALID_SEEK_POS) { + if(null != seekRequest && TrackProviderProto.INVALID_SEEK_POS != seekRequest.offsetBytes) { // We have a seek request. // Your code may take any reasonable time to fulfil the seek request, e.g. it can reopen http connection with appropriate offset, etc. // Poweramp just waits for the seek result packet (the waiting is limited by the user-set timeout). // Now we should either send appropriate seek result packet or close the connection (e.g. on some error). // Poweramp ignores any other packets sent before the seek result packet. - if(LOG) Log.w(TAG, "handleSeekRequest seekRequestPos=" + seekRequest + " fileLength=" + fileLength); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleSeekRequest seekRequestPos=" + seekRequest + " fileLength=" + fileLength); // NOTE: we could seek track here based on seekRequest.ms field. // In this case we still need to send back newPos as new byte offset. @@ -1087,10 +1086,10 @@ private boolean handleSeekRequest2(@NonNull TrackProviderProto proto, @Nullable // For the sake of testing, we'll seek track properly here, but will send "fake" newPos - long newPos = seekTrack(fc, seekRequest.offsetBytes, fileLength); + final long newPos = this.seekTrack(fc, seekRequest.offsetBytes, fileLength); final long fakeAverageBytesPerMs = 116; // ~116 bytes per ms in bensound-dubstep.flac - long fakeNewPos = seekRequest.ms * fakeAverageBytesPerMs; + final long fakeNewPos = seekRequest.ms * fakeAverageBytesPerMs; proto.sendSeekResult(fakeNewPos); return true; @@ -1102,10 +1101,10 @@ private boolean handleSeekRequest2(@NonNull TrackProviderProto proto, @Nullable * THREADING: worker thread. * @return new position within the track, or <0 on error * */ - private long seekTrack(@NonNull FileChannel channel, long seekPosBytes, long fileLength) { + private long seekTrack(@NonNull final FileChannel channel, final long seekPosBytes, final long fileLength) { // Out seeking is simple as we just seek the FileChannel try { - if(seekPosBytes >= 0) { + if(0 <= seekPosBytes) { channel.position(seekPosBytes); } else { // If seekPos < 0, this is a seek request from the end of the file channel.position(fileLength + seekPosBytes); @@ -1113,8 +1112,8 @@ private long seekTrack(@NonNull FileChannel channel, long seekPosBytes, long fil return channel.position(); - } catch(IOException ex) { - Log.e(TAG, "seekPosBytes=" + seekPosBytes, ex); + } catch(final IOException ex) { + Log.e(ExampleProvider.TAG, "seekPosBytes=" + seekPosBytes, ex); return -1; } } @@ -1123,21 +1122,21 @@ private long seekTrack(@NonNull FileChannel channel, long seekPosBytes, long fil * For tracks available on the device as file, it's much easier to send direct file descriptor pointing to the file itself. The file descriptor is seekable * and track can be reopened multiple times in this case, e.g. if tags, seek-wave, or album art scanning is needed. */ - private ParcelFileDescriptor openViaDirectFD(@NonNull String documentId, @NonNull String filePath) throws FileNotFoundException { - if(LOG) Log.w(TAG, "openViaDirectFD documentId=" + documentId + " filePath=" + filePath); + private ParcelFileDescriptor openViaDirectFD(@NonNull final String documentId, @NonNull final String filePath) throws FileNotFoundException { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openViaDirectFD documentId=" + documentId + " filePath=" + filePath); try { - if(USE_MP3_COPY) { - File file = new File(getContext().getFilesDir(), filePath); + if(ExampleProvider.USE_MP3_COPY) { + final File file = new File(this.getContext().getFilesDir(), filePath); return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } else { - AssetFileDescriptor afd = getContext().getResources().getAssets().openFd(filePath); - ParcelFileDescriptor pfd = afd.getParcelFileDescriptor(); + final AssetFileDescriptor afd = this.getContext().getResources().getAssets().openFd(filePath); + final ParcelFileDescriptor pfd = afd.getParcelFileDescriptor(); Os.lseek(pfd.getFileDescriptor(), afd.getStartOffset(), OsConstants.SEEK_SET); - if(LOG) Log.w(TAG, "openDocument afd.offset=" + afd.getStartOffset() + " len=" + afd.getLength() + " lseek=" + Os.lseek(pfd.getFileDescriptor(), 0, OsConstants.SEEK_CUR)); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "openDocument afd.offset=" + afd.getStartOffset() + " len=" + afd.getLength() + " lseek=" + Os.lseek(pfd.getFileDescriptor(), 0, OsConstants.SEEK_CUR)); return pfd; } - } catch(Throwable th) { - Log.e(TAG, "documentId=" + documentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "documentId=" + documentId, th); throw new FileNotFoundException(documentId); } } @@ -1146,19 +1145,19 @@ private ParcelFileDescriptor openViaDirectFD(@NonNull String documentId, @NonNul * Implementing CALL_GET_URL here to return dynamic URL for given track. Document uri is passed as string in arg */ @Override - public Bundle call(String method, String arg, Bundle extras) { - Bundle res = super.call(method, arg, extras); - if(res == null) { + public Bundle call(final String method, final String arg, final Bundle extras) { + final Bundle res = super.call(method, arg, extras); + if(null == res) { if(TrackProviderConsts.CALL_GET_URL.equals(method)) { - return handleGetUrl(arg, extras); + return this.handleGetUrl(arg, extras); } else if(TrackProviderConsts.CALL_RESCAN.equals(method)) { - return handleRescan(arg, extras); + return this.handleRescan(arg, extras); } else if(TrackProviderConsts.CALL_GET_DIR_METADATA.equals(method)) { - return handleGetDirMetadata(arg, extras); + return this.handleGetDirMetadata(arg, extras); - } else Log.e(TAG, "call bad method=" + method, new Exception()); + } else Log.e(ExampleProvider.TAG, "call bad method=" + method, new Exception()); } return res; } @@ -1167,15 +1166,15 @@ public Bundle call(String method, String arg, Bundle extras) { * Returns dynamic URL for given track. Document uri is passed as string in arg * @return bundle with the appropriate data is expected, or null error */ - private Bundle handleGetUrl(String arg, Bundle extras) { + private Bundle handleGetUrl(final String arg, final Bundle extras) { if(TextUtils.isEmpty(arg)) throw new IllegalArgumentException(arg); - Uri uri = Uri.parse(arg); - enforceTree(uri); - String documentId = DocumentsContract.getDocumentId(uri); - if(documentId.endsWith(DOCID_DYNAMIC_URL_SUFFIX)) { - boolean isDubstep = documentId.contains("dubstep"); - Bundle res = new Bundle(); - String url = isDubstep ? DUBSTEP_HTTP_URL : SUMMER_HTTP_URL; + final Uri uri = Uri.parse(arg); + this.enforceTree(uri); + final String documentId = DocumentsContract.getDocumentId(uri); + if(documentId.endsWith(ExampleProvider.DOCID_DYNAMIC_URL_SUFFIX)) { + final boolean isDubstep = documentId.contains("dubstep"); + final Bundle res = new Bundle(); + final String url = isDubstep ? ExampleProvider.DUBSTEP_HTTP_URL : ExampleProvider.SUMMER_HTTP_URL; res.putString(TrackProviderConsts.COLUMN_URL, url); // Optionally add some headers to send with given url. These headers are used just once for this track playback and are not persisted @@ -1187,9 +1186,9 @@ private Bundle handleGetUrl(String arg, Bundle extras) { // Optionally set some http method. By default it's GET, setting GET here for the demonstration purpose res.putString(TrackProviderConsts.COLUMN_HTTP_METHOD, "GET"); - if(LOG) Log.w(TAG, "call CALL_GET_URL url=>" + url); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "call CALL_GET_URL url=>" + url); return res; - } else Log.e(TAG, "call CALL_GET_URL bad documentId=" + documentId, new Exception()); + } else Log.e(ExampleProvider.TAG, "call CALL_GET_URL bad documentId=" + documentId, new Exception()); return null; } @@ -1204,28 +1203,28 @@ private Bundle handleGetUrl(String arg, Bundle extras) { * If we're sending the rescan intent from this app (see {@link MainActivity#sendScanThisSubdir(View)}), we're getting the extras * we sent. */ - private Bundle handleRescan(String arg, Bundle extras) { - if(LOG) Log.w(TAG, "handleRescan extras=" + dumpBundle(extras)); + private Bundle handleRescan(final String arg, final Bundle extras) { + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleRescan extras=" + ExampleProvider.dumpBundle(extras)); // Analyze optional EXTRA_PROVIDER and EXTRA_PATH here. // If EXTRA_PROVIDER matches this provider, we may update the cached remote data - String targetProvider = extras.getString(PowerampAPI.Scanner.EXTRA_PROVIDER); + final String targetProvider = extras.getString(PowerampAPI.Scanner.EXTRA_PROVIDER); - if(TextUtils.equals(targetProvider, getContext().getPackageName())) { // Assuming authority == package name for this provider + if(TextUtils.equals(targetProvider, this.getContext().getPackageName())) { // Assuming authority == package name for this provider - String path = extras.getString(PowerampAPI.Scanner.EXTRA_PATH); + final String path = extras.getString(PowerampAPI.Scanner.EXTRA_PATH); if(!TextUtils.isEmpty(path)) { // - update data just for the EXTRA_PATH sub-directory hierarchy - if(LOG) Log.w(TAG, "handleRescan targeted rescan path=" + path); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleRescan targeted rescan path=" + path); } else { // - update data from the remote server - if(LOG) Log.w(TAG, "handleRescan targeted provider rescan"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleRescan targeted provider rescan"); } } else //noinspection StatementWithEmptyBody @@ -1241,7 +1240,7 @@ private Bundle handleRescan(String arg, Bundle extras) { // - force update all data - if(LOG) Log.w(TAG, "handleRescan forced full update"); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleRescan forced full update"); } @@ -1256,55 +1255,55 @@ private Bundle handleRescan(String arg, Bundle extras) { * @param arg the directory uri * @return bundle filled with extras: {@link TrackProviderConsts#EXTRA_ANCESTORS} */ - private Bundle handleGetDirMetadata(String arg, Bundle extras) { - Uri uri = Uri.parse(arg); - enforceTree(uri); + private Bundle handleGetDirMetadata(final String arg, final Bundle extras) { + final Uri uri = Uri.parse(arg); + this.enforceTree(uri); // DocumentId for the directory which hierarchy (up to the root) Poweramp wants to retrieve - String docId = DocumentsContract.getDocumentId(uri); + final String docId = DocumentsContract.getDocumentId(uri); // We should return array of ancestor documentIds for given documentId from root to the direct parent of the given documentId // As for this provider, we have full path information in the document id itself, we just provide at as is. // Real provider may additionally specifically process the directory docId as needed to generate the valid hierarchy path - String[] segments = docId.split("/"); + final String[] segments = docId.split("/"); - if(segments.length <= 1) { // If we have just one segment, this is a root documentId and no parents exist - if(LOG) Log.w(TAG, "handleGetDirMetadata IGNORE ROOT docId=" + docId + " uri=" + uri); + if(1 >= segments.length) { // If we have just one segment, this is a root documentId and no parents exist + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleGetDirMetadata IGNORE ROOT docId=" + docId + " uri=" + uri); return Bundle.EMPTY; } - StringBuilder sb = new StringBuilder(); - String[] ancestors = new String[segments.length - 1]; // We want to return all ancestor document ids from root to parent dir, not including the dir in question + final StringBuilder sb = new StringBuilder(); + final String[] ancestors = new String[segments.length - 1]; // We want to return all ancestor document ids from root to parent dir, not including the dir in question for(int i = 0; i < ancestors.length; i++) { sb.append(segments[i]); ancestors[i] = sb.toString(); // Return full documentId for each ancestor sb.append('/'); } - Bundle res = new Bundle(); + final Bundle res = new Bundle(); res.putStringArray(TrackProviderConsts.EXTRA_ANCESTORS, ancestors); - if(LOG) Log.w(TAG, "handleGetDirMetadata uri=" + uri + " docId=" + docId + " ancestors=" + Arrays.toString(ancestors) + " res=" + dumpBundle(res)); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "handleGetDirMetadata uri=" + uri + " docId=" + docId + " ancestors=" + Arrays.toString(ancestors) + " res=" + ExampleProvider.dumpBundle(res)); return res; } /** We need to override this DocumentProvider API method, which is called by super class to check if given documentId is a correct child of parentDocumentId */ @Override - public boolean isChildDocument(String parentDocumentId, String documentId) { + public boolean isChildDocument(final String parentDocumentId, final String documentId) { try { // As our hierarchy is defined by assets/, we could just return true here, but for a sake of example, let's verify that given documentId is inside the folder // This is track, we randomly generate track entries, so we can't verify them - boolean res = documentId.endsWith(".mp3") || documentId.endsWith(".m3u8") || documentId.endsWith(DOCID_STATIC_URL_SUFFIX) - || documentId.startsWith(parentDocumentId) && isAssetDir(getContext().getResources().getAssets(), documentId); + final boolean res = documentId.endsWith(".mp3") || documentId.endsWith(".m3u8") || documentId.endsWith(ExampleProvider.DOCID_STATIC_URL_SUFFIX) + || documentId.startsWith(parentDocumentId) && this.isAssetDir(this.getContext().getResources().getAssets(), documentId); - if(LOG) Log.w(TAG, "isChildDocument =>" + res + " parentDocumentId=" + parentDocumentId + " documentId=" + documentId); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "isChildDocument =>" + res + " parentDocumentId=" + parentDocumentId + " documentId=" + documentId); return res; - } catch(Throwable th) { - Log.e(TAG, "parentDocumentId=" + parentDocumentId + " documentId=" + documentId, th); + } catch(final Throwable th) { + Log.e(ExampleProvider.TAG, "parentDocumentId=" + parentDocumentId + " documentId=" + documentId, th); } return false; } @@ -1313,44 +1312,44 @@ public boolean isChildDocument(String parentDocumentId, String documentId) { * Very inefficient way of checking folders vs files in assets, but Android SDK doesn't provide anything better. * This shouldn't be used in production providers anyway */ - private boolean isAssetDir(AssetManager assets, @NonNull String path) { + private boolean isAssetDir(final AssetManager assets, @NonNull final String path) { // Ignore empty.txt return !path.endsWith("/empty.txt"); } - private long getAssetFileSize(AssetManager assets, String path) { + private long getAssetFileSize(final AssetManager assets, final String path) { try { - try(AssetFileDescriptor afd = assets.openFd(path)) { + try(final AssetFileDescriptor afd = assets.openFd(path)) { return afd.getLength(); } - } catch(IOException ex) { + } catch(final IOException ex) { return 0L; } } - private static String[] resolveRootProjection(String[] projection) { - return projection != null ? projection : DEFAULT_ROOT_PROJECTION; + private static String[] resolveRootProjection(final String[] projection) { + return null != projection ? projection : ExampleProvider.DEFAULT_ROOT_PROJECTION; } - private static String[] resolveDocumentProjection(String[] projection) { - return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; + private static String[] resolveDocumentProjection(final String[] projection) { + return null != projection ? projection : ExampleProvider.DEFAULT_DOCUMENT_PROJECTION; } - private static String[] resolveTrackProjection(String[] projection) { - return projection != null ? projection : DEFAULT_TRACK_AND_METADATA_PROJECTION; + private static String[] resolveTrackProjection(final String[] projection) { + return null != projection ? projection : ExampleProvider.DEFAULT_TRACK_AND_METADATA_PROJECTION; } /** Assumes docId is track path, thus we can extract digits after - and before .mp3, e.g. trackNum = 10 for dubstep-10.mp3 */ - private static int extractTrackNum(String docId) { - int startIx = docId.lastIndexOf('-'); - int endIx = docId.lastIndexOf('.'); - if(startIx < 0 || endIx < 0 || startIx >= endIx) { + private static int extractTrackNum(final String docId) { + final int startIx = docId.lastIndexOf('-'); + final int endIx = docId.lastIndexOf('.'); + if(0 > startIx || 0 > endIx || startIx >= endIx) { return 0; } try { return Integer.parseInt(docId.substring(startIx + 1, endIx), 10); - } catch(NumberFormatException ex) { - Log.e(TAG, "docId=" + docId, ex); + } catch(final NumberFormatException ex) { + Log.e(ExampleProvider.TAG, "docId=" + docId, ex); } return 0; } @@ -1360,10 +1359,11 @@ private static int extractTrackNum(String docId) { * NOTE: for /foo/bar/file.mp3 it returns file.mp3, but for /foo/bar or /foo/bar/ it returns bar, so it assumes folder path, not any path * @param path should be a _folder_ path */ - @SuppressWarnings("null") - private static @NonNull String getShortDirName(@NonNull String path) { + @SuppressWarnings("null") + @NonNull + private static String getShortDirName(@NonNull final String path) { int ix = path.lastIndexOf('/'); - if(ix == -1) { + if(-1 == ix) { return path; } int end = path.length(); @@ -1378,43 +1378,44 @@ private static int extractTrackNum(String docId) { /** * @return last segment of the path (after the last /), this is usually filename with extension, or the path itself if no slashes */ - @SuppressWarnings("null") - private static @NonNull String getShortName(@NonNull String path) { + @SuppressWarnings("null") + @NonNull + private static String getShortName(@NonNull final String path) { int ix = path.lastIndexOf('/'); // - if(ix == -1) { + if(-1 == ix) { ix = path.lastIndexOf('\\'); } - if(ix == -1) { + if(-1 == ix) { return path; } return path.substring(ix + 1); } /** To provide direct file descriptors, we need to have tracks extracted to local filesystem files */ - private void copyAsset(String assetFile, File targetDir, boolean overwrite) { - File outFile = new File(targetDir, getShortName(assetFile)); + private void copyAsset(final String assetFile, final File targetDir, final boolean overwrite) { + final File outFile = new File(targetDir, ExampleProvider.getShortName(assetFile)); if(!overwrite && outFile.exists()) { - if(LOG) Log.w(TAG, "copyAsset IGNORE exists assetFile=" + assetFile + " =>" + outFile); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "copyAsset IGNORE exists assetFile=" + assetFile + " =>" + outFile); return; } try { - try(InputStream in = getContext().getResources().getAssets().open(assetFile)) { - try(OutputStream out = new FileOutputStream(outFile)) { - byte[] buffer = new byte[16 * 1024]; + try(final InputStream in = this.getContext().getResources().getAssets().open(assetFile)) { + try(final OutputStream out = new FileOutputStream(outFile)) { + final byte[] buffer = new byte[16 * 1024]; int read; - while((read = in.read(buffer)) != -1){ + while(-1 != (read = in.read(buffer))){ out.write(buffer, 0, read); } } } - if(LOG) Log.w(TAG, "copyAsset assetFile=" + assetFile + " =>" + outFile); - } catch(IOException ex) { - Log.e(TAG, "", ex); + if(ExampleProvider.LOG) Log.w(ExampleProvider.TAG, "copyAsset assetFile=" + assetFile + " =>" + outFile); + } catch(final IOException ex) { + Log.e(ExampleProvider.TAG, "", ex); } } - private boolean arrayContains(@NonNull T[] array, T needle) { - for(T item : array) { + private boolean arrayContains(@NonNull final T[] array, final T needle) { + for(final T item : array) { if(Objects.equals(item, needle)) { //if(LOG) Log.w(TAG, "arrayContains FOUND needle=" + needle); return true; @@ -1424,51 +1425,53 @@ private boolean arrayContains(@NonNull T[] array, T needle) { return false; } - private @Nullable String capitalize(@Nullable String documentId) { - if(documentId != null && documentId.length() > 0) { + @Nullable + private String capitalize(@Nullable final String documentId) { + if(null != documentId && 0 < documentId.length()) { return Character.toUpperCase(documentId.charAt(0)) + documentId.substring(1); } return documentId; } @SuppressLint("NewApi") - private void enforceTree(Uri documentUri) { + private void enforceTree(final Uri documentUri) { if(DocumentsContract.isTreeUri(documentUri)) { // Exists in SDK=21, but hidden there - final String parent = DocumentsContract.getTreeDocumentId(documentUri); - final String child = DocumentsContract.getDocumentId(documentUri); + String parent = DocumentsContract.getTreeDocumentId(documentUri); + String child = DocumentsContract.getDocumentId(documentUri); if (Objects.equals(parent, child)) { return; } - if (!isChildDocument(parent, child)) { + if (!this.isChildDocument(parent, child)) { throw new SecurityException( "Document " + child + " is not a descendant of " + parent); } } } - private static void closeSilently(@Nullable Closeable c) { - if(c != null) { + private static void closeSilently(@Nullable final Closeable c) { + if(null != c) { try { c.close(); - } catch(IOException ex) { - Log.e(TAG, "", ex); + } catch(final IOException ex) { + Log.e(ExampleProvider.TAG, "", ex); } } } @SuppressWarnings("null") - private static @NonNull String dumpBundle(@Nullable Bundle bundle) { - if(bundle == null) { + @NonNull + private static String dumpBundle(@Nullable final Bundle bundle) { + if(null == bundle) { return "null bundle"; } - StringBuilder sb = new StringBuilder(); - Set keys = bundle.keySet(); + final StringBuilder sb = new StringBuilder(); + final Set keys = bundle.keySet(); sb.append("\n"); - for(String key : keys) { + for(final String key : keys) { sb.append('\t').append(key).append("="); - Object val = bundle.get(key); + final Object val = bundle.get(key); sb.append(val); - if(val != null) { + if(null != val) { sb.append(" ").append(val.getClass().getSimpleName()); } sb.append("\n"); diff --git a/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/MainActivity.java b/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/MainActivity.java index 3ac6bdc3..86aaf17a 100644 --- a/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/MainActivity.java +++ b/poweramp_provider_example/src/main/java/com/maxmpz/powerampproviderexample/MainActivity.java @@ -22,35 +22,35 @@ public class MainActivity extends Activity { private final BroadcastReceiver mScanEventsReceiver = new BroadcastReceiver() { @Override - public void onReceive(Context context, Intent intent) { - ((TextView)findViewById(R.id.status)).setText(intent.getAction()); + public void onReceive(final Context context, final Intent intent) { + ((TextView) MainActivity.this.findViewById(R.id.status)).setText(intent.getAction()); } }; @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - IntentFilter intentFilter = new IntentFilter(); + final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PowerampAPI.Scanner.ACTION_DIRS_SCAN_STARTED); intentFilter.addAction(PowerampAPI.Scanner.ACTION_DIRS_SCAN_FINISHED); intentFilter.addAction(PowerampAPI.Scanner.ACTION_FAST_TAGS_SCAN_FINISHED); intentFilter.addAction(PowerampAPI.Scanner.ACTION_TAGS_SCAN_STARTED); intentFilter.addAction(PowerampAPI.Scanner.ACTION_TAGS_SCAN_FINISHED); - registerReceiver(mScanEventsReceiver, intentFilter); + this.registerReceiver(this.mScanEventsReceiver, intentFilter); } - public void openPAMusicFolders(View view) { - if(LOG) Log.w(TAG, "openPAMusicFolders"); + public void openPAMusicFolders(final View view) { + if(MainActivity.LOG) Log.w(MainActivity.TAG, "openPAMusicFolders"); - Intent intent = new Intent(); + final Intent intent = new Intent(); intent.setComponent(new ComponentName(PowerampAPIHelper.getPowerampPackageName(this), PowerampAPI.ACTIVITY_SETTINGS)); intent.putExtra(PowerampAPI.Settings.EXTRA_OPEN_PATH, "library/music_folders_button"); intent.putExtra(PowerampAPI.Settings.EXTRA_NO_BACKSTACK, true); - intent.putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); - startActivity(intent); + intent.putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); + this.startActivity(intent); } // NOTE: depending on the "background" state of this app and Poweramp some methods may work or not in Android 8+ due to the background limitation. @@ -59,11 +59,11 @@ public void openPAMusicFolders(View view) { // starting such activity from background application may be not possible. // It's also possible to start scan via startService (not demonstrated here) - subject to the similar limitations - can't be started from the background app. - public void sendScan(View view) { - if(LOG) Log.w(TAG, "sendScan"); - Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) - .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, getPackageName() + " rescan") - .putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()); + public void sendScan(final View view) { + if(MainActivity.LOG) Log.w(MainActivity.TAG, "sendScan"); + final Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) + .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, this.getPackageName() + " rescan") + .putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()); try { // This won't work if Poweramp is on the background (not playing or Poweramp UI is not visible) @@ -76,31 +76,31 @@ public void sendScan(View view) { // This won't work if started from background service, but works fine for starting from the activity intent.setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); - startActivity(intent); + this.startActivity(intent); - } catch(Throwable th) { - Log.w(TAG, "", th); + } catch(final Throwable th) { + Log.w(MainActivity.TAG, "", th); } } - public void sendScanThis(View view) { - if(LOG) Log.w(TAG, "sendScanThis"); - Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) - .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, getPackageName() + " rescan") + public void sendScanThis(final View view) { + if(MainActivity.LOG) Log.w(MainActivity.TAG, "sendScanThis"); + final Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) + .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, this.getPackageName() + " rescan") .putExtra(PowerampAPI.Scanner.EXTRA_PROVIDER, "com.maxmpz.powerampproviderexample") // Our provider authority (matches pak name in this case) - .putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()) + .putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()) .setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); try { - startActivity(intent); - } catch(Throwable th) { - Log.w(TAG, "", th); + this.startActivity(intent); + } catch(final Throwable th) { + Log.w(MainActivity.TAG, "", th); } } - public void sendScanThisSubdir(View view) { - if(LOG) Log.w(TAG, "sendScanThisSubdir"); - Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) - .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, getPackageName() + " rescan") + public void sendScanThisSubdir(final View view) { + if(MainActivity.LOG) Log.w(MainActivity.TAG, "sendScanThisSubdir"); + final Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) + .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, this.getPackageName() + " rescan") .putExtra(PowerampAPI.Scanner.EXTRA_PROVIDER, "com.maxmpz.powerampproviderexample") // Our provider authority (matches pak name in this case) // This rescans everything under root1 // The path format is {@code /opaque-treeId/opaque-documentId/}: @@ -109,20 +109,20 @@ public void sendScanThisSubdir(View view) { // Poweramp uses GLOB and just adds "*" to the EXTRA_PATH, thus, in our case, Poweramp will search for root1/* folders/files. // Last slash is required here so we avoid matching e.g. root123/. .putExtra(PowerampAPI.Scanner.EXTRA_PATH, "root1/") - .putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()) + .putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()) //.putExtra(PowerampAPI.Scanner.EXTRA_FAST_SCAN, true) // If specified, Poweramp will only scan tracks if parent folder lastModified changed .setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); try { - startActivity(intent); - } catch(Throwable th) { - Log.w(TAG, "", th); + this.startActivity(intent); + } catch(final Throwable th) { + Log.w(MainActivity.TAG, "", th); } } - public void sendScanThisSubdir2(View view) { - if(LOG) Log.w(TAG, "sendScanThisSubdir2"); - Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) - .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, getPackageName() + " rescan") + public void sendScanThisSubdir2(final View view) { + if(MainActivity.LOG) Log.w(MainActivity.TAG, "sendScanThisSubdir2"); + final Intent intent = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS) + .putExtra(PowerampAPI.Scanner.EXTRA_CAUSE, this.getPackageName() + " rescan") .putExtra(PowerampAPI.Scanner.EXTRA_PROVIDER, "com.maxmpz.powerampproviderexample") // Our provider authority (matches pak name in this case) // This rescans everything under root1/Folder2 subpath. // The path format is {@code /opaque-treeId/opaque-documentId/}: @@ -133,21 +133,21 @@ public void sendScanThisSubdir2(View view) { // e.g. for file: @com.maxmpz.powerampproviderexample/root1/root1%2FFolder2%2Fdubstep-8.mp3. // Again, the EXTRA_PATH depends on how THIS provider defines and exposes paths/documentIds .putExtra(PowerampAPI.Scanner.EXTRA_PATH, Uri.encode("root1") + "/" + Uri.encode("root1/Folder2")) - .putExtra(PowerampAPI.EXTRA_PACKAGE, getPackageName()) + .putExtra(PowerampAPI.EXTRA_PACKAGE, this.getPackageName()) //.putExtra(PowerampAPI.Scanner.EXTRA_FAST_SCAN, true) // If specified, Poweramp will only scan tracks if parent folder lastModified changed .setComponent(PowerampAPIHelper.getApiActivityComponentName(this)); try { - startActivity(intent); - } catch(Throwable th) { - Log.w(TAG, "", th); + this.startActivity(intent); + } catch(final Throwable th) { + Log.w(MainActivity.TAG, "", th); } } @Override protected void onDestroy() { try { - unregisterReceiver(mScanEventsReceiver); - } catch(Throwable ignored) { } + this.unregisterReceiver(this.mScanEventsReceiver); + } catch(final Throwable ignored) { } super.onDestroy(); } } diff --git a/poweramp_skin_sample/src/main/java/com/poweramp/v3/sampleskin/SkinInfoActivity.java b/poweramp_skin_sample/src/main/java/com/poweramp/v3/sampleskin/SkinInfoActivity.java index da7e2ab5..4a9fafab 100644 --- a/poweramp_skin_sample/src/main/java/com/poweramp/v3/sampleskin/SkinInfoActivity.java +++ b/poweramp_skin_sample/src/main/java/com/poweramp/v3/sampleskin/SkinInfoActivity.java @@ -13,7 +13,7 @@ public class SkinInfoActivity extends Activity { private static final String TAG = "SkinInfoActivity"; @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_skin_info); } @@ -22,61 +22,61 @@ protected void onCreate(Bundle savedInstanceState) { * @return resolved Poweramp package name or null if not installed * NOTE: can be called from any thread, though double initialization is possible, but it's OK */ - public static String getPowerampPackageName(Context context) { + public static String getPowerampPackageName(final Context context) { try { - ResolveInfo info = context.getPackageManager().resolveService(new Intent("com.maxmpz.audioplayer.API_COMMAND"), 0); - if(info != null && info.serviceInfo != null) { + final ResolveInfo info = context.getPackageManager().resolveService(new Intent("com.maxmpz.audioplayer.API_COMMAND"), 0); + if(null != info && null != info.serviceInfo) { return info.serviceInfo.packageName; } - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(SkinInfoActivity.TAG, "", th); } return null; } - public void startWithSampleSkin(View view) { - String pak = getPowerampPackageName(this); - if(pak == null) { + public void startWithSampleSkin(final View view) { + final String pak = SkinInfoActivity.getPowerampPackageName(this); + if(null == pak) { Toast.makeText(this, R.string.skin_poweramp_not_installed, Toast.LENGTH_LONG).show(); return; } - Intent intent = new Intent(Intent.ACTION_MAIN) + final Intent intent = new Intent(Intent.ACTION_MAIN) .setClassName(pak, "com.maxmpz.audioplayer.StartupActivity") - .putExtra("theme_pak", getPackageName()) + .putExtra("theme_pak", this.getPackageName()) .putExtra("theme_id", R.style.SampleSkin); - startActivity(intent); + this.startActivity(intent); //Toast.makeText(this, R.string.skin_applied_msg, Toast.LENGTH_LONG).show(); // Enable toast if needed - finish(); + this.finish(); } - public void startWithSampleAAASkin(View view) { - String pak = getPowerampPackageName(this); - if(pak == null) { + public void startWithSampleAAASkin(final View view) { + final String pak = SkinInfoActivity.getPowerampPackageName(this); + if(null == pak) { Toast.makeText(this, R.string.skin_poweramp_not_installed, Toast.LENGTH_LONG).show(); return; } - Intent intent = new Intent(Intent.ACTION_MAIN) + final Intent intent = new Intent(Intent.ACTION_MAIN) .setClassName(pak, "com.maxmpz.audioplayer.StartupActivity") - .putExtra("theme_pak", getPackageName()) + .putExtra("theme_pak", this.getPackageName()) .putExtra("theme_id", R.style.SampleSkinAAA); - startActivity(intent); + this.startActivity(intent); //Toast.makeText(this, R.string.skin_applied_msg, Toast.LENGTH_LONG).show(); // Enable toast if needed - finish(); + this.finish(); } - public void openPowerampThemeSettings(View view) { - String pak = getPowerampPackageName(this); - if(pak == null) { + public void openPowerampThemeSettings(final View view) { + final String pak = SkinInfoActivity.getPowerampPackageName(this); + if(null == pak) { Toast.makeText(this, R.string.skin_poweramp_not_installed, Toast.LENGTH_LONG).show(); return; } - Intent intent = new Intent(Intent.ACTION_MAIN) + final Intent intent = new Intent(Intent.ACTION_MAIN) .setClassName(pak, "com.maxmpz.audioplayer.SettingsActivity") .putExtra("open", "theme") - .putExtra("theme_pak", getPackageName()) // If theme_pak/theme_id specified for open/theme, will scroll to/opens this skins settings + .putExtra("theme_pak", this.getPackageName()) // If theme_pak/theme_id specified for open/theme, will scroll to/opens this skins settings .putExtra("theme_id", R.style.SampleSkin); - startActivity(intent); - finish(); + this.startActivity(intent); + this.finish(); } } diff --git a/poweramp_vis_presets_example/src/main/java/com/poweramp/v3/vispresets/sample/InfoActivity.java b/poweramp_vis_presets_example/src/main/java/com/poweramp/v3/vispresets/sample/InfoActivity.java index c1b14c0a..90561f2b 100644 --- a/poweramp_vis_presets_example/src/main/java/com/poweramp/v3/vispresets/sample/InfoActivity.java +++ b/poweramp_vis_presets_example/src/main/java/com/poweramp/v3/vispresets/sample/InfoActivity.java @@ -38,51 +38,51 @@ public class InfoActivity extends Activity { @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_info); - EditText edit = findViewById(R.id.edit); + final EditText edit = this.findViewById(R.id.edit); // Inject some preset as text - try(InputStreamReader isr = new InputStreamReader(getResources().getAssets().open("milk_presets/Example - example-bars-vertical.milk"), StandardCharsets.UTF_8)) { - final StringBuilder out = new StringBuilder(); + try(final InputStreamReader isr = new InputStreamReader(this.getResources().getAssets().open("milk_presets/Example - example-bars-vertical.milk"), StandardCharsets.UTF_8)) { + StringBuilder out = new StringBuilder(); int charsRead; final int bufferSize = 1024; - final char[] buffer = new char[bufferSize]; - while((charsRead = isr.read(buffer, 0, buffer.length)) > 0) { + char[] buffer = new char[bufferSize]; + while(0 < (charsRead = isr.read(buffer, 0, buffer.length))) { out.append(buffer, 0, charsRead); } edit.setText(out); - } catch(IOException e) { - Log.e(TAG, "", e); + } catch(final IOException e) { + Log.e(InfoActivity.TAG, "", e); } } /** * This opens Poweramp and rescans appropriate preset APK - as specified in {@link PowerampAPI.Settings#EXTRA_VIS_PRESETS_PAK} extra */ - public void startWithVisPresets(View view) { - Intent intent = new Intent(Intent.ACTION_MAIN) + public void startWithVisPresets(final View view) { + final Intent intent = new Intent(Intent.ACTION_MAIN) .setClassName(PowerampAPIHelper.getPowerampPackageName(this), PowerampAPI.ACTIVITY_STARTUP) - .putExtra(PowerampAPI.Settings.EXTRA_VIS_PRESETS_PAK, getPackageName()); - startActivity(intent); - finish(); + .putExtra(PowerampAPI.Settings.EXTRA_VIS_PRESETS_PAK, this.getPackageName()); + this.startActivity(intent); + this.finish(); } /** * This opens Poweramp settings and scrolls to the appropriate preset APK - as specified in {@link PowerampAPI.Settings#EXTRA_VIS_PRESETS_PAK} extra, * but this doesn't rescan presets */ - public void openPowerampVisSettings(View view) { - Intent intent = new Intent(Intent.ACTION_MAIN) + public void openPowerampVisSettings(final View view) { + final Intent intent = new Intent(Intent.ACTION_MAIN) .setClassName(PowerampAPIHelper.getPowerampPackageName(this), PowerampAPI.Settings.ACTIVITY_SETTINGS) .putExtra(PowerampAPI.Settings.EXTRA_OPEN, PowerampAPI.Settings.OPEN_VIS) - .putExtra(PowerampAPI.Settings.EXTRA_VIS_PRESETS_PAK, getPackageName()) // If vis_presets_pak specified for open/theme, will scroll presets list to this apk entry + .putExtra(PowerampAPI.Settings.EXTRA_VIS_PRESETS_PAK, this.getPackageName()) // If vis_presets_pak specified for open/theme, will scroll presets list to this apk entry ; - startActivity(intent); - finish(); + this.startActivity(intent); + this.finish(); } /** @@ -90,23 +90,23 @@ public void openPowerampVisSettings(View view) { * This works only if current application is foreground, meaning this can't be used from the background service (Android 8+), as * Android will block background service execution. */ - public void rescanVisPresets(View view) { - Intent intent = new Intent(PowerampAPI.MilkScanner.ACTION_SCAN) + public void rescanVisPresets(final View view) { + final Intent intent = new Intent(PowerampAPI.MilkScanner.ACTION_SCAN) .setComponent(PowerampAPIHelper.getMilkScannerServiceComponentName(this)) .putExtra(PowerampAPI.MilkScanner.EXTRA_CAUSE, "Manual rescan") - .putExtra(PowerampAPI.MilkScanner.EXTRA_PACKAGE, getPackageName()); - startService(intent); + .putExtra(PowerampAPI.MilkScanner.EXTRA_PACKAGE, this.getPackageName()); + this.startService(intent); } - public void sendPreset(View view) { + public void sendPreset(final View view) { // Issue SET_VIS_PRESET - Intent intent = new Intent(PowerampAPI.ACTION_API_COMMAND) + final Intent intent = new Intent(PowerampAPI.ACTION_API_COMMAND) .setComponent(PowerampAPIHelper.getApiActivityComponentName(this)) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.SET_VIS_PRESET) .putExtra(PowerampAPI.EXTRA_NAME, "VisPresetsExample - Test Preset.milk") - .putExtra(PowerampAPI.EXTRA_DATA, ((EditText) findViewById(R.id.edit)).getText().toString()); // NOTE: strictly String type is expected - startActivity(intent); + .putExtra(PowerampAPI.EXTRA_DATA, ((EditText) this.findViewById(R.id.edit)).getText().toString()); // NOTE: strictly String type is expected + this.startActivity(intent); // NOTE: we can't immediately do same action/component startActivity immediately, so delay it a bit via post new Handler(Looper.getMainLooper()).post(new Runnable() { @@ -117,16 +117,16 @@ public void run() { // NOTE: Poweramp won't change interface in reflection to just changing this preference. But as we're currently inside other activity, // re-opening Poweramp UI will re-read this preference. Though, this may fail for e.g. split screen when both activities are always on top - Bundle request = new Bundle(); + final Bundle request = new Bundle(); request.putInt("vis_mode", PowerampAPI.Settings.PreferencesConsts.VIS_MODE_VIS_W_UI); // See PowerampAPI.Settings.Preferences - getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_SET_PREFERENCE, null, request); + InfoActivity.this.getContentResolver().call(PowerampAPI.ROOT_URI, PowerampAPI.CALL_SET_PREFERENCE, null, request); // Now open Poweramp UI main screen intent = new Intent(PowerampAPI.ACTION_OPEN_MAIN) .setClassName(PowerampAPIHelper.getPowerampPackageName(InfoActivity.this), PowerampAPI.ACTIVITY_STARTUP) ; - startActivity(intent); + InfoActivity.this.startActivity(intent); // And command it to play something @@ -134,43 +134,43 @@ public void run() { .setComponent(PowerampAPIHelper.getApiActivityComponentName(InfoActivity.this)) .putExtra(PowerampAPI.EXTRA_COMMAND, PowerampAPI.Commands.RESUME) ; - startActivity(intent); + InfoActivity.this.startActivity(intent); } }); } - public void listMilkPresets(View view) { - if(Build.VERSION.SDK_INT < 23) { + public void listMilkPresets(final View view) { + if(23 > Build.VERSION.SDK_INT) { // We shouldn't do this for Androids below 10. Instead directly access files as needed // Poweramp still supports this functionality for lower Androids, but due to the permission access used, we may ask it directly // here for Android 5 - listMilkPresetsImpl(); + this.listMilkPresetsImpl(); return; } - if(checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS) != PackageManager.PERMISSION_GRANTED) { - if(LOG) Log.w(TAG, "listMilkPresets requesting permission"); - requestPermissions(new String[] { PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS }, REQUEST_ACCESS_MILK_PRESETS); + if(PackageManager.PERMISSION_GRANTED != checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS)) { + if(InfoActivity.LOG) Log.w(InfoActivity.TAG, "listMilkPresets requesting permission"); + this.requestPermissions(new String[] { PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS }, InfoActivity.REQUEST_ACCESS_MILK_PRESETS); } else { - listMilkPresetsImpl(); + this.listMilkPresetsImpl(); } } @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if(requestCode == REQUEST_ACCESS_MILK_PRESETS && grantResults != null && grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED + public void onRequestPermissionsResult(final int requestCode, final String[] permissions, final int[] grantResults) { + if(REQUEST_ACCESS_MILK_PRESETS == requestCode && null != grantResults && 0 < grantResults.length + && PackageManager.PERMISSION_GRANTED == grantResults[0] ) { - if(LOG) Log.w(TAG, "onRequestPermissionsResult PERMISSION_GRANTED"); - listMilkPresetsImpl(); + if(InfoActivity.LOG) Log.w(InfoActivity.TAG, "onRequestPermissionsResult PERMISSION_GRANTED"); + this.listMilkPresetsImpl(); - } else if(LOG) Log.e(TAG, "onRequestPermissionsResult !PERMISSION_GRANTED requestCode=" + requestCode + + } else if(InfoActivity.LOG) Log.e(InfoActivity.TAG, "onRequestPermissionsResult !PERMISSION_GRANTED requestCode=" + requestCode + " permissions=" + Arrays.toString(permissions) + " grantResults=" + Arrays.toString(grantResults)); } - private String getExtension(String filename) { - int lastDot = filename.lastIndexOf('.'); - if(lastDot == -1 || lastDot == filename.length() - 1) { + private String getExtension(final String filename) { + final int lastDot = filename.lastIndexOf('.'); + if(-1 == lastDot || lastDot == filename.length() - 1) { return ""; } return filename.substring(lastDot + 1); @@ -178,10 +178,10 @@ private String getExtension(String filename) { @SuppressWarnings("CommentedOutCode") public void listMilkPresetsImpl() { - if(LOG) Log.w(TAG, "listMilkPresetsImpl"); - final ArrayList presets = new ArrayList<>(); - final ArrayList textures = new ArrayList<>(); - final ArrayList zips = new ArrayList<>(); + if(InfoActivity.LOG) Log.w(InfoActivity.TAG, "listMilkPresetsImpl"); + ArrayList presets = new ArrayList<>(); + ArrayList textures = new ArrayList<>(); + ArrayList zips = new ArrayList<>(); // The path parameter also accepts glob patterns, e.g. content://com.maxmpz.audioplayer.milk_presets/*.milk, // To quickly query for the single file, you can also use uris like: content://com.maxmpz.audioplayer.milk_presets/single_file @@ -189,30 +189,30 @@ public void listMilkPresetsImpl() { // Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED, Document.COLUMN_SIZE, // NOTE: ? symbol requires escaping (%3F) - Uri uri = PowerampAPI.MILK_PRESETS_URI; + final Uri uri = PowerampAPI.MILK_PRESETS_URI; //Uri uri = Uri.parse("content://com.maxmpz.audioplayer.milk_presets"); //Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath("*.milk").build(); //Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath("*.{jpg|jpeg|png|tga|bmp}").build(); //Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath("file.???").build(); //Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath("*.???").build(); - try(Cursor c = getContentResolver().query(uri, null, null, null, null)) { - while(c != null && c.moveToNext()) { - String fileName = c.getString(0); - long lastModified = c.getLong(1); - long size = c.getLong(2); + try(final Cursor c = this.getContentResolver().query(uri, null, null, null, null)) { + while(null != c && c.moveToNext()) { + final String fileName = c.getString(0); + final long lastModified = c.getLong(1); + final long size = c.getLong(2); - if(LOG) Log.w(TAG, "listMilkPresetsImpl fileName=" + fileName + " lastModified=" + lastModified + " size=" + size); + if(InfoActivity.LOG) Log.w(InfoActivity.TAG, "listMilkPresetsImpl fileName=" + fileName + " lastModified=" + lastModified + " size=" + size); - String ext = getExtension(fileName).toLowerCase(Locale.ROOT); // NOTE: Poweramp is not case sensitive for presets + final String ext = this.getExtension(fileName).toLowerCase(Locale.ROOT); // NOTE: Poweramp is not case sensitive for presets switch(ext) { case "zip": - Log.w(TAG, "listMilkPresetsImpl FOUND zip=" + fileName); + Log.w(InfoActivity.TAG, "listMilkPresetsImpl FOUND zip=" + fileName); zips.add(fileName); break; case "prjm": case "milk": - Log.w(TAG, "listMilkPresetsImpl FOUND milk preset=" + fileName); + Log.w(InfoActivity.TAG, "listMilkPresetsImpl FOUND milk preset=" + fileName); presets.add(fileName); break; case "jpeg": @@ -220,7 +220,7 @@ public void listMilkPresetsImpl() { case "png": case "tga": case "bmp": - Log.w(TAG, "listMilkPresetsImpl FOUND texture=" + fileName); + Log.w(InfoActivity.TAG, "listMilkPresetsImpl FOUND texture=" + fileName); textures.add(fileName); break; } @@ -236,34 +236,34 @@ public void listMilkPresetsImpl() { .setPositiveButton(android.R.string.ok, null) .show(); - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(InfoActivity.TAG, "", th); } } - public void pushFile(View view) { + public void pushFile(final View view) { // Assume we asked for permission earlier in list milk presets - if(Build.VERSION.SDK_INT >= 23 && checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS) != PackageManager.PERMISSION_GRANTED) { - Log.e(TAG, "pushFile !permission"); + if(23 <= Build.VERSION.SDK_INT && PackageManager.PERMISSION_GRANTED != checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS)) { + Log.e(InfoActivity.TAG, "pushFile !permission"); return; } - String newFile = "TestPreset - " + System.currentTimeMillis() + ".milk"; + final String newFile = "TestPreset - " + System.currentTimeMillis() + ".milk"; - Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath(newFile).build(); - try(ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, "wt")) { - if(pfd != null) { - try(OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(pfd.getFileDescriptor()))) { - EditText edit = findViewById(R.id.edit); + final Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath(newFile).build(); + try(final ParcelFileDescriptor pfd = this.getContentResolver().openFileDescriptor(uri, "wt")) { + if(null != pfd) { + try(final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(pfd.getFileDescriptor()), StandardCharsets.UTF_8)) { + final EditText edit = this.findViewById(R.id.edit); writer.write(edit.getText().toString()); } } // Ask Poweramp to rescan - rescanVisPresets(null); + this.rescanVisPresets(null); - mPushedFiles.add(newFile); + this.mPushedFiles.add(newFile); new AlertDialog.Builder(this) .setTitle("pushFile") @@ -271,19 +271,19 @@ public void pushFile(View view) { .setPositiveButton(android.R.string.ok, null) .show(); - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(InfoActivity.TAG, "", th); } } - public void deleteFile(View view) { + public void deleteFile(final View view) { // Assume we asked for permission earlier in list milk presets - if(Build.VERSION.SDK_INT >= 23 && checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS) != PackageManager.PERMISSION_GRANTED) { - Log.e(TAG, "deleteFile !permission"); + if(23 <= Build.VERSION.SDK_INT && PackageManager.PERMISSION_GRANTED != checkSelfPermission(PowerampAPI.PERMISSION_ACCESS_MILK_PRESETS)) { + Log.e(InfoActivity.TAG, "deleteFile !permission"); return; } - if(mPushedFiles.size() == 0) { // We need some files previously pushed in this app session + if(0 == mPushedFiles.size()) { // We need some files previously pushed in this app session new AlertDialog.Builder(this) .setTitle("deleteFile") .setMessage("No pushed files to delete yet") @@ -292,24 +292,24 @@ public void deleteFile(View view) { return; } - String fileToDelete = mPushedFiles.get(mPushedFiles.size() - 1); // Delete last file pushed - mPushedFiles.remove(mPushedFiles.size() - 1); + final String fileToDelete = this.mPushedFiles.get(this.mPushedFiles.size() - 1); // Delete last file pushed + this.mPushedFiles.remove(this.mPushedFiles.size() - 1); - Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath(fileToDelete).build(); + final Uri uri = PowerampAPI.MILK_PRESETS_URI.buildUpon().appendPath(fileToDelete).build(); try{ - int deleted = getContentResolver().delete(uri, null, null); - if(deleted != 0) { + final int deleted = this.getContentResolver().delete(uri, null, null); + if(0 != deleted) { // Ask Poweramp to rescan - rescanVisPresets(null); + this.rescanVisPresets(null); } new AlertDialog.Builder(this) .setTitle("deleteFile") - .setMessage(deleted != 0 ? "Deleted file=" + fileToDelete : "No files deleted") + .setMessage(0 != deleted ? "Deleted file=" + fileToDelete : "No files deleted") .setPositiveButton(android.R.string.ok, null) .show(); - } catch(Throwable th) { - Log.e(TAG, "", th); + } catch(final Throwable th) { + Log.e(InfoActivity.TAG, "", th); } }