Use Androidx compat's toolbar instead of actionbars.

ListView's multiselect still uses actionbar.
This commit is contained in:
Dennis Guse
2019-10-17 21:19:14 +02:00
parent ed9b4c8f3d
commit ac5a9ea65d
18 changed files with 187 additions and 138 deletions
@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
/**
* @author Jimmy Shih
@@ -34,6 +35,9 @@ public abstract class AbstractActivity extends AppCompatActivity {
setVolumeControlStream(TextToSpeech.Engine.DEFAULT_STREAM);
setContentView(getLayoutResId());
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
/**
@@ -16,23 +16,7 @@
package de.dennisguse.opentracks;
import android.app.Activity;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import androidx.appcompat.widget.SearchView;
import java.util.ArrayList;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment.ConfirmDeleteCaller;
@@ -57,115 +41,6 @@ public abstract class AbstractListActivity extends AbstractActivity implements C
protected static final int GPS_REQUEST_CODE = 6;
private static final int DELETE_REQUEST_CODE = 3;
public static void configureListViewContextualMenu(final ListView listView, final ContextualActionModeCallback contextualActionModeCallback) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.list_context_menu, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
contextualActionModeCallback.onPrepare(menu, getCheckedPositions(listView), listView.getCheckedItemIds(), true);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
// Do nothing
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
mode.invalidate();
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (contextualActionModeCallback.onClick(item.getItemId(), getCheckedPositions(listView), listView.getCheckedItemIds())) {
mode.finish();
}
return true;
}
/**
* Gets the checked positions in a list view.
*
* @param list the list view
*/
private int[] getCheckedPositions(ListView list) {
SparseBooleanArray positions = list.getCheckedItemPositions();
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < positions.size(); i++) {
int key = positions.keyAt(i);
if (positions.valueAt(i)) {
arrayList.add(key);
}
}
int[] result = new int[arrayList.size()];
for (int i = 0; i < arrayList.size(); i++) {
result[i] = arrayList.get(i);
}
return result;
}
});
}
public static void configureSearchWidget(Activity activity, final MenuItem menuItem, final TrackController trackController) {
final SearchView searchView = (SearchView) menuItem.getActionView();
SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
//NOTE: for some reason activity.getComponentName() did not trigger the SearchListActivity
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(activity, SearchListActivity.class)));
} else {
Log.w(TAG, "Could not retrieve SearchManager.");
}
searchView.setQueryRefinementEnabled(true);
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
// Hide and show trackController when searchable widget has focus/no focus
if (trackController != null) {
if (hasFocus) {
trackController.hide();
} else {
trackController.show();
}
}
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
menuItem.collapseActionView();
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
menuItem.collapseActionView();
return false;
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == DELETE_REQUEST_CODE) {
@@ -46,6 +46,7 @@ import de.dennisguse.opentracks.content.Waypoint.WaypointType;
import de.dennisguse.opentracks.content.WaypointsColumns;
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -175,7 +176,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
}
};
listView.setAdapter(resourceCursorAdapter);
AbstractListActivity.configureListViewContextualMenu(listView, contextualActionModeCallback);
ActivityUtils.configureListViewContextualMenu(listView, contextualActionModeCallback);
LoaderManager.getInstance(this).initLoader(0, null, new LoaderCallbacks<Cursor>() {
@NonNull
@@ -234,7 +235,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
insertMarkerMenuItem = menu.findItem(R.id.marker_list_insert_marker);
searchMenuItem = menu.findItem(R.id.marker_list_search);
AbstractListActivity.configureSearchWidget(this, searchMenuItem, null);
ActivityUtils.configureSearchWidget(this, searchMenuItem, null);
return super.onCreateOptionsMenu(menu);
}
@@ -55,6 +55,7 @@ import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment;
import de.dennisguse.opentracks.fragments.DeleteMarkerDialogFragment.DeleteMarkerCaller;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.stats.TripStatistics;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -223,7 +224,7 @@ public class SearchListActivity extends AbstractListActivity implements DeleteMa
startActivity(intent);
}
});
AbstractListActivity.configureListViewContextualMenu(listView, contextualActionModeCallback);
ActivityUtils.configureListViewContextualMenu(listView, contextualActionModeCallback);
handleIntent(getIntent());
}
@@ -130,11 +130,11 @@ public class TrackController {
handlerUpdateTotalTime.removeCallbacks(updateTotalTimeRunnable);
}
void hide() {
public void hide() {
containerView.setVisibility(View.GONE);
}
void show() {
public void show() {
containerView.setVisibility(View.VISIBLE);
}
@@ -59,6 +59,7 @@ import de.dennisguse.opentracks.fragments.ConfirmDeleteDialogFragment;
import de.dennisguse.opentracks.services.ITrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
import de.dennisguse.opentracks.settings.SettingsActivity;
import de.dennisguse.opentracks.util.ActivityUtils;
import de.dennisguse.opentracks.util.IntentUtils;
import de.dennisguse.opentracks.util.ListItemUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@@ -325,9 +326,8 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
}
};
listView.setAdapter(resourceCursorAdapter);
TrackListActivity.this.registerForContextMenu(listView);
AbstractListActivity.configureListViewContextualMenu(listView, contextualActionModeCallback);
ActivityUtils.configureListViewContextualMenu(listView, contextualActionModeCallback);
LoaderManager.getInstance(this).initLoader(0, null, loaderCallbacks);
showStartupDialogs();
@@ -389,7 +389,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
getMenuInflater().inflate(R.menu.track_list, menu);
searchMenuItem = menu.findItem(R.id.track_list_search);
AbstractListActivity.configureSearchWidget(this, searchMenuItem, trackController);
ActivityUtils.configureSearchWidget(this, searchMenuItem, trackController);
startGpsMenuItem = menu.findItem(R.id.track_list_start_gps);
aggregatedStatisticsMenuItem = menu.findItem(R.id.track_list_aggregated_statistics);
@@ -0,0 +1,137 @@
package de.dennisguse.opentracks.util;
import android.app.Activity;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import androidx.appcompat.widget.SearchView;
import java.util.ArrayList;
import de.dennisguse.opentracks.ContextualActionModeCallback;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.SearchListActivity;
import de.dennisguse.opentracks.TrackController;
public class ActivityUtils {
private static final String TAG = ActivityUtils.class.getSimpleName();
public static void configureListViewContextualMenu(final ListView listView, final ContextualActionModeCallback contextualActionModeCallback) {
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.list_context_menu, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
contextualActionModeCallback.onPrepare(menu, getCheckedPositions(listView), listView.getCheckedItemIds(), true);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
// Do nothing
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
mode.invalidate();
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (contextualActionModeCallback.onClick(item.getItemId(), getCheckedPositions(listView), listView.getCheckedItemIds())) {
mode.finish();
}
return true;
}
/**
* Gets the checked positions in a list view.
*
* @param list the list view
*/
private int[] getCheckedPositions(ListView list) {
SparseBooleanArray positions = list.getCheckedItemPositions();
ArrayList<Integer> arrayList = new ArrayList<>();
for (int i = 0; i < positions.size(); i++) {
int key = positions.keyAt(i);
if (positions.valueAt(i)) {
arrayList.add(key);
}
}
int[] result = new int[arrayList.size()];
for (int i = 0; i < arrayList.size(); i++) {
result[i] = arrayList.get(i);
}
return result;
}
});
}
public static void configureSearchWidget(Activity activity, final MenuItem menuItem, final TrackController trackController) {
final SearchView searchView = (SearchView) menuItem.getActionView();
SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
//NOTE: for some reason activity.getComponentName() did not trigger the SearchListActivity
searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(activity, SearchListActivity.class)));
} else {
Log.w(TAG, "Could not retrieve SearchManager.");
}
searchView.setQueryRefinementEnabled(true);
searchView.setSubmitButtonEnabled(true);
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
// Hide and show trackController when searchable widget has focus/no focus
if (trackController != null) {
if (hasFocus) {
trackController.hide();
} else {
trackController.show();
}
}
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
menuItem.collapseActionView();
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
menuItem.collapseActionView();
return false;
}
});
}
}
+4 -1
View File
@@ -16,7 +16,10 @@ limitations under the License.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false">
android:baselineAligned="false"
android:orientation="horizontal">
<include layout="@layout/toolbar" />
<include layout="@layout/track_controller" />
+2
View File
@@ -4,6 +4,8 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
@@ -17,6 +17,8 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/toolbar" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/maker_detail_activity_view_pager"
android:layout_width="match_parent"
+2
View File
@@ -18,6 +18,8 @@ limitations under the License.
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ScrollView style="@style/ScrollView.WithBottomButtons">
<LinearLayout
+6 -3
View File
@@ -13,9 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ListView
android:id="@+id/marker_list"
@@ -26,4 +29,4 @@ limitations under the License.
android:id="@+id/marker_list_empty"
style="@style/ListEmptyTextView"
android:text="@string/marker_list_empty_message" />
</merge>
</LinearLayout>
+2
View File
@@ -17,6 +17,8 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/toolbar" />
<ListView
android:id="@+id/search_list"
android:layout_width="match_parent"
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize" />
</merge>
+2
View File
@@ -18,6 +18,8 @@ limitations under the License.
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<TabHost
android:id="@+id/tackdetail_tabhost"
android:layout_width="match_parent"
+2
View File
@@ -18,6 +18,8 @@ limitations under the License.
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ScrollView style="@style/ScrollView.WithBottomButtons">
<LinearLayout
+2
View File
@@ -18,6 +18,8 @@ limitations under the License.
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<ListView
android:id="@+id/track_list"
android:layout_width="match_parent"
+2 -1
View File
@@ -15,7 +15,7 @@ limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="ThemeCustom" parent="Theme.AppCompat">
<style name="ThemeCustom" parent="Theme.AppCompat.NoActionBar">
<!-- TODO Cleanup necessary due to change to appcompat -->
<!-- Auto generated -->
<item name="android:activatedBackgroundIndicator">@drawable/activated_background_holo_dark
@@ -34,6 +34,7 @@ limitations under the License.
<!-- <item name="colorPrimaryDark">TODO</item>-->
<item name="android:colorAccent">@color/holo_orange_dark</item>
<item name="windowActionModeOverlay">true</item>
</style>
<style name="ThemeCustomTransparent" parent="ThemeCustom">