Skip to content
Permalink
Browse files

Android SDK compatibility updates.

Play Store requires targetSdkVersion=28, and the Support Library
(renamed to androidx) is no longer compatible with minSdkVersion<14.

I'm bumping the version number to 4.0 because this breaks compatibility
with Android releases prior to Ice Cream Sandwich.
  • Loading branch information...
pmarks-net committed Jun 24, 2019
1 parent a324388 commit 68a51f41d79b39e0a4d818786e96892f68a578c0
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 23
compileSdkVersion 29

defaultConfig {
applicationId 'net.pmarks.chromadoze'
minSdkVersion 8
targetSdkVersion 23
minSdkVersion 14
targetSdkVersion 29
}

buildTypes {
@@ -18,6 +18,5 @@ android {
}

dependencies {
implementation 'com.android.support:support-v4:23.4.0'
implementation 'com.android.support:appcompat-v7:23.4.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
}
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.pmarks.chromadoze"
android:versionCode="25"
android:versionName="3.7.1">
android:versionCode="26"
android:versionName="4.0">

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- Note: We explicitly do NOT want fullBackupOnly="true" here.
Android 6.0 should use our backupAgent instead of the service-killing
@@ -7,7 +7,7 @@
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.CursorAdapter;
import android.widget.CursorAdapter;

/**
* A subclass of {@link android.widget.CursorAdapter} that provides reordering
@@ -21,12 +21,13 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.fragment.app.Fragment;

public class AboutFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -24,14 +24,6 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
@@ -43,6 +35,15 @@
import android.widget.ImageButton;
import android.widget.Spinner;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.MenuItemCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import java.util.Date;

public class ChromaDoze extends AppCompatActivity implements
@@ -138,16 +139,12 @@ protected void onPause() {

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem mi;

mi = menu.add(0, MENU_PLAY_STOP, 0, getString(R.string.play_stop));
MenuItemCompat
.setShowAsAction(mi, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
menu.add(0, MENU_PLAY_STOP, 0, getString(R.string.play_stop)).setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS);

if (mFragmentId == FragmentIndex.ID_CHROMA_DOZE) {
mi = menu.add(0, MENU_LOCK, 0, getString(R.string.lock_unlock));
MenuItemCompat.setShowAsAction(mi,
MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
menu.add(0, MENU_LOCK, 0, getString(R.string.lock_unlock)).setShowAsAction(
MenuItem.SHOW_AS_ACTION_ALWAYS);
}

return super.onCreateOptionsMenu(menu);
@@ -25,10 +25,11 @@
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.annotation.NonNull;

public class EqualizerView extends android.view.View implements UIState.LockListener {
private static final int BAND_COUNT = SpectrumData.BAND_COUNT;

@@ -56,11 +57,6 @@

public EqualizerView(Context context, AttributeSet attrs) {
super(context, attrs);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// On the Nexus S, hardware acceleration breaks Path.offset(),
// and it seems unnecessary for our tiny polygons.
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
makeColors();
}

@@ -18,13 +18,14 @@
package net.pmarks.chromadoze;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.fragment.app.Fragment;

import java.text.DateFormat;
import java.util.Date;

@@ -18,14 +18,15 @@
package net.pmarks.chromadoze;

import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;

import androidx.fragment.app.ListFragment;

import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import com.mobeta.android.dslv.DragSortListView.RemoveListener;
@@ -18,6 +18,8 @@
package net.pmarks.chromadoze;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
@@ -28,14 +30,14 @@
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RemoteViews;
import android.widget.TextView;

import junit.framework.Assert;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import java.util.ArrayList;
import java.util.Date;
@@ -59,6 +61,7 @@

private static final int NOTIFY_ID = 1;
private PowerManager.WakeLock mWakeLock;
private static final String CHANNEL_ID = "chromadoze_default";

private int lastStartId = -1;

@@ -67,7 +70,9 @@
private static class PercentHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Assert.assertEquals(PERCENT_MSG, msg.what);
if (msg.what != PERCENT_MSG) {
throw new AssertionError("Unexpected message: " + msg.what);
}
updatePercent(msg.arg1);
}
}
@@ -80,10 +85,24 @@ public void onCreate() {
mSampleShuffler = new SampleShuffler(params);
mSampleGenerator = new SampleGenerator(this, params, mSampleShuffler);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ChromaDoze Wake Lock");
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "chromadoze:NoiseService");
mWakeLock.acquire();

startForeground(NOTIFY_ID, makeNotify());
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}

startForeground(NOTIFY_ID, makeNotify(false));

// Note: This leaks memory if I use "this" instead of "getApplicationContext()".
mAudioFocusHelper = new AudioFocusHelper(
@@ -158,37 +177,38 @@ public IBinder onBind(Intent intent) {
}

// Create an icon for the notification bar.
private Notification makeNotify() {
// android:launchMode="singleTask" ensures that the latest instance
// of the Activity will be reachable from the Launcher. However, a
// naive Intent can still overwrite the task, so we track down the
// existing task by pretending to be the Launcher.
PendingIntent contentIntent = PendingIntent.getActivity(
this,
0,
new Intent(this, ChromaDoze.class)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER),
0);

Notification n = new NotificationCompat.Builder(this)
private Notification makeNotify(boolean preview) {
NotificationCompat.Builder b = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_bars)
.setWhen(0)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.notification_text))
.setContentIntent(contentIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.build();

// Add a Stop button to the Notification bar. Not trying to support
// this pre-ICS, because the click detection and styling are weird.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
addButtonToNotification(n);
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);

// We actually build the Notification twice:
// 1. With preview=true (recursively), to extract its RemoteViews.
// 2. With preview=false, using a ContentView assembled from the preview.
if (!preview) {
// android:launchMode="singleTask" ensures that the latest instance
// of the Activity will be reachable from the Launcher. However, a
// naive Intent can still overwrite the task, so we track down the
// existing task by pretending to be the Launcher.
b.setContentIntent(PendingIntent.getActivity(
this,
0,
new Intent(this, ChromaDoze.class)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER),
0));

// Add a Stop button to the Notification bar.
b.setCustomContentView(addButtonToNotification(makeNotify(true)));
}
return n;

return b.build();
}

private void addButtonToNotification(Notification n) {
private RemoteViews addButtonToNotification(Notification n) {
// Create a new RV with a Stop button.
RemoteViews rv = new RemoteViews(
getPackageName(), R.layout.notification_with_stop_button);
@@ -200,21 +220,29 @@ private void addButtonToNotification(Notification n) {
rv.setOnClickPendingIntent(R.id.stop_button, pendingIntent);

// Pre-render the original RV, and copy some of the colors.
final View inflated = n.contentView.apply(this, new FrameLayout(this));
RemoteViews oldRV = getContentView(this, n);
final View inflated = oldRV.apply(this, new FrameLayout(this));
final TextView titleText = findTextView(inflated, getString(R.string.app_name));
final TextView defaultText = findTextView(inflated, getString(R.string.notification_text));
rv.setInt(R.id.divider, "setBackgroundColor", defaultText.getTextColors().getDefaultColor());
rv.setInt(R.id.stop_button_square, "setBackgroundColor", titleText.getTextColors().getDefaultColor());

// Insert a copy of the original RV into the new one.
rv.addView(R.id.notification_insert, n.contentView.clone());
rv.addView(R.id.notification_insert, oldRV.clone());

return rv;
}

// Splice everything back into the original's root view.
int id = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "android");
n.contentView.removeAllViews(id);
n.contentView.addView(id, rv);
private static RemoteViews getContentView(Context context, Notification n) {
if (n.contentView != null) {
return n.contentView;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Notification.Builder.recoverBuilder(context, n).createContentView();
}
throw new IllegalStateException("Failed to build a ContentView");
}


private static TextView findTextView(View view, String title) {
if (view instanceof TextView) {
TextView text = (TextView) view;
@@ -18,8 +18,6 @@
package net.pmarks.chromadoze;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +27,9 @@
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.Fragment;

public class OptionsFragment extends Fragment implements OnSeekBarChangeListener, OnCheckedChangeListener {
private UIState mUiState;
private SeekBar mMinVolSeek;
@@ -21,8 +21,6 @@
import android.content.Intent;
import android.content.SharedPreferences;

import junit.framework.Assert;

import java.util.ArrayList;

public class UIState {
@@ -138,7 +136,7 @@ public boolean getLocked() {
}

public void setLockBusy(boolean busy) {
Assert.assertTrue(mLocked);
if (!mLocked) throw new AssertionError("Expected mLocked");
if (mLockBusy != busy) {
mLockBusy = busy;
notifyLockListeners(LockListener.LockEvent.BUSY);
@@ -4,7 +4,7 @@
android:layout_height="match_parent"
android:orientation="vertical">

<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
@@ -14,7 +14,7 @@
android:id="@+id/nav_spinner"
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
</android.support.v7.widget.Toolbar>
</androidx.appcompat.widget.Toolbar>

<FrameLayout
android:id="@+id/fragment_container"

0 comments on commit 68a51f4

Please sign in to comment.
You can’t perform that action at this time.