forked from upstream-mirrors/OpenTracks
Use Androidx compat's toolbar instead of actionbars.
ListView's multiselect still uses actionbar.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user