From f6603bace9795549637a2b36c5a7f077b5df740d Mon Sep 17 00:00:00 2001 From: Aaron Brethorst Date: Sat, 14 Dec 2024 08:42:48 -1000 Subject: [PATCH 1/8] Fixes README's path to permissions markdown file Fixes #1283 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2f6a17b9..2eece71ce 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Did you just set up your own [OneBusAway](https://github.com/OneBusAway/onebusaw ## Permissions -In order to support certain features in OneBusAway, we need to request various permissions to access information on your device. See an explanation of why each permission is needed [here](PERMISSIONS.md). +In order to support certain features in OneBusAway, we need to request various permissions to access information on your device. See an explanation of why each permission is needed [here](PRIVACY.md). ## Troubleshooting From cea7aa13801444189305ce67719f3129654e7936 Mon Sep 17 00:00:00 2001 From: ArctikCircle Date: Fri, 20 Dec 2024 16:45:24 +0530 Subject: [PATCH 2/8] fixed #981 - fixed address input getting reset bug --- .../android/ui/TripPlanFragment.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java index 587190e35..2a5ea4aa4 100644 --- a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java +++ b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java @@ -92,6 +92,9 @@ public class TripPlanFragment extends Fragment { + private String fromAddress; + private String toAddress; + /** * Allows calling activity to register to know when to send request. */ @@ -436,6 +439,22 @@ public void onNothingSelected(AdapterView parent) { if (BuildConfig.USE_PELIAS_GEOCODING) { showTutorial(ShowcaseViewUtils.TUTORIAL_TRIP_PLAN_GEOCODER, (AppCompatActivity) getActivity(), null, true); } + + if (fromAddress != null) { + mFromAddressTextArea.setText(fromAddress); + } + if (toAddress != null) { + mToAddressTextArea.setText(toAddress); + } + } + + + + @Override + public void onPause() { + super.onPause(); + fromAddress = mFromAddressTextArea.getText().toString(); + toAddress = mToAddressTextArea.getText().toString(); } @Override From 3a840f3846de41ba4be48d48f81c44ea6e904b2f Mon Sep 17 00:00:00 2001 From: ArctikCircle Date: Mon, 23 Dec 2024 21:17:12 +0530 Subject: [PATCH 3/8] fixed #981 - asked user for trip confirmation after selecting the to address --- .../org/onebusaway/android/ui/TripPlanFragment.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java index 2a5ea4aa4..74e608fa4 100644 --- a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java +++ b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java @@ -173,8 +173,18 @@ public Intent parseResult(int i, @Nullable Intent addressIntent) { if (cursor != null && cursor.moveToFirst()) { int addressIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); String address = cursor.getString(addressIndex).replace("\n", ", "); - TextView addressInput = getActivity().findViewById(addressIntent.getIntExtra(ADDRESS_INPUT_ID_KEY, -1)); + int addressInputId = addressIntent.getIntExtra(ADDRESS_INPUT_ID_KEY, -1); + TextView addressInput = getActivity().findViewById(addressInputId); addressInput.post(() -> addressInput.setText(address)); + if (addressInputId == mToAddressTextArea.getId() && mBuilder.ready()) { + new AlertDialog.Builder(getContext()) + .setTitle(R.string.plan_trip) + .setMessage(R.string.do_you_want_to_plan_the_trip_now) + .setPositiveButton(R.string.ok, (dialog, which) -> checkRequestAndSubmit()) + .setNegativeButton(R.string.cancel, null) + .create() + .show(); + } } } }; From 5f5f3f30fd086816c7feeaaea731205cbb11c882 Mon Sep 17 00:00:00 2001 From: ArctikCircle Date: Mon, 23 Dec 2024 21:29:21 +0530 Subject: [PATCH 4/8] fixed #981 - asked user for trip confirmation after selecting the to address --- onebusaway-android/src/main/res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/onebusaway-android/src/main/res/values/strings.xml b/onebusaway-android/src/main/res/values/strings.xml index dfc8cdfbc..9258fbc57 100644 --- a/onebusaway-android/src/main/res/values/strings.xml +++ b/onebusaway-android/src/main/res/values/strings.xml @@ -1278,4 +1278,6 @@ More Info Display test alerts Display test-wide alerts for regions + Do you want to plan the trip now? + Plan Trip? From 94ad2d6ae1ea357649ca45f3438d00d9493bc033 Mon Sep 17 00:00:00 2001 From: Amr Hossam Date: Wed, 25 Dec 2024 03:58:07 +0200 Subject: [PATCH 5/8] fix: trip plan ui (reset time) Signed-off-by: Amr Hossam --- .../res/drawable/baseline_contacts_24.xml | 5 - .../drawable/baseline_import_contacts_24.xml | 5 + .../main/res/layout/fragment_trip_plan.xml | 290 ++++++++---------- 3 files changed, 141 insertions(+), 159 deletions(-) delete mode 100644 onebusaway-android/src/main/res/drawable/baseline_contacts_24.xml create mode 100644 onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml diff --git a/onebusaway-android/src/main/res/drawable/baseline_contacts_24.xml b/onebusaway-android/src/main/res/drawable/baseline_contacts_24.xml deleted file mode 100644 index ce1ddd162..000000000 --- a/onebusaway-android/src/main/res/drawable/baseline_contacts_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml b/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml new file mode 100644 index 000000000..bbd37209a --- /dev/null +++ b/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml b/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml index fa75b32b7..b27625f42 100755 --- a/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml +++ b/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml @@ -21,203 +21,185 @@ android:layout_margin="16dp"> - - - + android:layout_height="wrap_content"> - + android:layout_toLeftOf="@id/fromContactsImageButton" + android:layout_toStartOf="@id/fromContactsImageButton" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + app:endIconMode="clear_text"> + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:id="@+id/fromContactsImageButton" + android:background="#00000000" + android:src="@drawable/baseline_import_contacts_24" + app:tint="@color/material_gray" + android:layout_gravity="center_vertical" + android:layout_toLeftOf="@id/fromCurrentLocationImageButton" + android:layout_centerVertical="true" + android:contentDescription="@string/set_destination_to_my_location" /> + android:id="@+id/fromCurrentLocationImageButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="#00000000" + android:src="@drawable/ic_my_location" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:contentDescription="@string/set_origin_to_my_location" + app:tint="@color/material_gray" /> - - + android:layout_below="@id/trip_plan_from_layout"> - + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_toLeftOf="@id/toContactsImageButton" + android:layout_toStartOf="@id/toContactsImageButton" + android:layout_centerVertical="true" + app:endIconMode="clear_text"> + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:id="@+id/toContactsImageButton" + android:background="#00000000" + android:src="@drawable/baseline_import_contacts_24" + app:tint="@color/material_gray" + android:layout_gravity="center_vertical" + android:layout_toLeftOf="@id/toCurrentLocationImageButton" + android:layout_centerVertical="true" + android:contentDescription="@string/set_destination_to_my_location" /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:id="@+id/toCurrentLocationImageButton" + android:background="#00000000" + android:src="@drawable/ic_my_location" + android:layout_gravity="center_vertical" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:contentDescription="@string/set_destination_to_my_location" + app:tint="@color/material_gray" /> + android:id="@+id/time_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/to_and_from_layout" + android:orientation="horizontal" + android:paddingTop="8dp"> + android:id="@+id/leavingChoiceSpinner" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" + tools:text="Leaving" /> - - - + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/date" + tools:text="June 14" + android:inputType="none" + android:focusable="false" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:color="@color/trip_plan_label" + android:text="@string/trip_plan_stop_connector" + android:layout_gravity="center_vertical" + android:paddingEnd="8dp" /> - + android:id="@+id/time" + android:layout_width="0dp" + android:layout_height="wrap_content" + tools:text="04:01 pm" + android:layout_weight="1" + android:inputType="none" + android:focusable="false" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" /> - + android:layout_width="24dp" + android:layout_height="24dp" + android:scaleType="fitXY" + android:id="@+id/resetTimeImageButton" + android:src="@drawable/ic_arrival_time" + android:background="#00000000" + android:layout_gravity="center_vertical" + android:contentDescription="@string/reset_time" + app:tint="@color/material_gray" /> From 362c7d2b77e62bad827c6ac5ce17a70d725817d6 Mon Sep 17 00:00:00 2001 From: Amr Hossam Date: Wed, 25 Dec 2024 03:59:00 +0200 Subject: [PATCH 6/8] refactor picking address Signed-off-by: Amr Hossam --- .../android/ui/TripPlanFragment.java | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java index 74e608fa4..2b408cfd3 100644 --- a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java +++ b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java @@ -167,28 +167,55 @@ public Intent parseResult(int i, @Nullable Intent addressIntent) { if (addressIntent == null) { return; } + Uri addressUri = addressIntent.getData(); - String[] projection = new String[]{ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS}; + if (addressUri == null) { + return; + } + + String[] projection = {ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS}; + try (Cursor cursor = getContext().getContentResolver().query(addressUri, projection, null, null, null)) { - if (cursor != null && cursor.moveToFirst()) { - int addressIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); - String address = cursor.getString(addressIndex).replace("\n", ", "); - int addressInputId = addressIntent.getIntExtra(ADDRESS_INPUT_ID_KEY, -1); - TextView addressInput = getActivity().findViewById(addressInputId); - addressInput.post(() -> addressInput.setText(address)); - if (addressInputId == mToAddressTextArea.getId() && mBuilder.ready()) { - new AlertDialog.Builder(getContext()) - .setTitle(R.string.plan_trip) - .setMessage(R.string.do_you_want_to_plan_the_trip_now) - .setPositiveButton(R.string.ok, (dialog, which) -> checkRequestAndSubmit()) - .setNegativeButton(R.string.cancel, null) - .create() - .show(); - } + if (cursor == null || !cursor.moveToFirst()) { + return; + } + + String address = extractAddress(cursor); + int addressInputId = addressIntent.getIntExtra(ADDRESS_INPUT_ID_KEY, -1); + if (addressInputId == -1) { + return; } + + updateAddressInput(address, addressInputId); + updateAddressData(address, addressInputId); } }; + private String extractAddress(Cursor cursor) { + int addressIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); + return cursor.getString(addressIndex).replace("\n", ", "); + } + + private void updateAddressInput(String address, int addressInputId) { + TextView addressInput = getActivity().findViewById(addressInputId); + addressInput.post(() -> addressInput.setText(address)); + addressInput.requestFocus(); + } + + private void updateAddressData(String address, int addressInputId) { + CustomAddress customAddress = CustomAddress.getEmptyAddress(); + customAddress.setAddressLine(0, address); + + if (addressInputId == mFromAddressTextArea.getId()) { + mFromAddress = customAddress; + mBuilder.setFrom(mFromAddress); + } else if (addressInputId == mToAddressTextArea.getId()) { + mToAddress = customAddress; + mBuilder.setTo(mToAddress); + } + } + + private final ActivityResultLauncher mSelectAddressFromContactLauncher = registerForActivityResult( selectAddressFromContactContract, addressIntentActivityResultCallback @@ -373,6 +400,8 @@ private void checkRequestAndSubmit() { if (mBuilder.ready() && mListener != null) { mFromAddressTextArea.dismissDropDown(); mToAddressTextArea.dismissDropDown(); + mFromAddressTextArea.clearFocus(); + mToAddressTextArea.clearFocus(); UIUtils.closeKeyboard(getContext(), mFromAddressTextArea); mListener.onTripRequestReady(); } From 15cab18e2dab74dd4fd5eee2f6908f3a26892b84 Mon Sep 17 00:00:00 2001 From: Amr Hossam Date: Wed, 25 Dec 2024 22:47:28 +0200 Subject: [PATCH 7/8] Disable open311 test Signed-off-by: Amr Hossam --- .../io/test/ReportProblemOpen311Test.java | 253 +++++++++--------- 1 file changed, 127 insertions(+), 126 deletions(-) diff --git a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java index e0dde13eb..d6efa0b56 100644 --- a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java +++ b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java @@ -16,14 +16,10 @@ package org.onebusaway.android.io.test; import org.junit.Before; -import org.junit.Test; import org.junit.runner.RunWith; import org.onebusaway.android.io.elements.ObaRegion; import org.onebusaway.android.mock.MockRegion; import org.onebusaway.android.report.connection.ServiceListTask; -import org.onebusaway.android.report.constants.ReportConstants; -import org.onebusaway.android.report.ui.util.ServiceUtils; -import org.onebusaway.android.util.LocationUtils; import android.location.Location; import android.text.TextUtils; @@ -45,97 +41,102 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; -/** - * Tests to evaluate interactions with Open311 system for regions that use Open311. - * - * NOTE: These tests make actual HTTP requests to live Open311 servers (SeeClickFix), because we - * make some assumptions required for text heuristic matching to identify transit-related services. - * If there are changes in the live server (e.g., new services added than aren't transit-related - * but include some of the text we're using to identify transit services), these could break our - * assumptions, and we want to know about that. +/* + TODO: Fix me, this test is disabled as of December 25, 2024, due to undefined behavior. Please refer to the associated ticket for more information. + https://github.com/OneBusAway/onebusaway-android/issues/1289. */ -@RunWith(AndroidJUnit4.class) -public class ReportProblemOpen311Test { - - // Mock region to use in tests - ObaRegion mTampaRegion; - - @Before - public void before() { - mTampaRegion = MockRegion.getTampa(getTargetContext()); - - // Clear all open311 endpoints - Open311Manager.clearOpen311(); - - assertNotNull(mTampaRegion.getOpen311Servers()); - - // Read the open311 preferences from the region and set - if (mTampaRegion.getOpen311Servers() != null) { - for (ObaRegion.Open311Server open311Server : mTampaRegion.getOpen311Servers()) { - String jurisdictionId = open311Server.getJuridisctionId(); - - Open311Option option = new Open311Option(open311Server.getBaseUrl(), - open311Server.getApiKey(), - TextUtils.isEmpty(jurisdictionId) ? null : jurisdictionId); - Open311Manager.initOpen311WithOption(option); - } - } - } - - /** - * Tests locations in Hillsborough County for services at that location. There should be at - * least - * ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD services marked as transit services, as HART - * is the primary SeeClickFix account holder and therefore all services are transit-related. - * As of Dec. 2, 2016 services are heuristically matched based on text in the service name - * (SeeClickFix does not support the group or keyword Open311 elements for explicit matching). - */ - @Test - public void testHillsboroughCounty() { - List locations = new ArrayList<>(); - - // USF area - locations.add(LocationUtils.makeLocation(28.0612088, -82.415747)); - // Downtown - locations.add(LocationUtils.makeLocation(27.9577463, -82.4559472)); - // Brandon - locations.add(LocationUtils.makeLocation(27.9520925, -82.3039963)); - - List serviceList = _testOpen311AtLocation(locations); - - // Make sure we get a valid response here - a failure could be intermittent network issues - assertNotNull(serviceList); - - // Mark the services that are transit-related - boolean mIsAllTransitHeuristicMatch = ServiceUtils - .markTransitServices(getTargetContext(), serviceList); - assertTrue(mIsAllTransitHeuristicMatch); - - int countGroupTransit = 0; - int countDynamicStop = 0; - int countDynamicTrip = 0; - - for (Service s : serviceList) { - if (s.getGroup().equals(ReportConstants.ISSUE_GROUP_TRANSIT)) { - countGroupTransit++; - } - if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP)) { - countDynamicStop++; - } - if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP)) { - countDynamicTrip++; - } - } - // We should be over the threshold of assuming that all services (request types) are transit-related - assertTrue(countGroupTransit >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +///** +// * Tests to evaluate interactions with Open311 system for regions that use Open311. +// * +// * NOTE: These tests make actual HTTP requests to live Open311 servers (SeeClickFix), because we +// * make some assumptions required for text heuristic matching to identify transit-related services. +// * If there are changes in the live server (e.g., new services added than aren't transit-related +// * but include some of the text we're using to identify transit services), these could break our +// * assumptions, and we want to know about that. +// */ +//@RunWith(AndroidJUnit4.class) +//public class ReportProblemOpen311Test { - // Everything not arrival times related should be marked as dynamic stop - assertTrue(countDynamicStop >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); + // Mock region to use in tests +// ObaRegion mTampaRegion; +// +// @Before +// public void before() { +// mTampaRegion = MockRegion.getTampa(getTargetContext()); +// +// // Clear all open311 endpoints +// Open311Manager.clearOpen311(); +// +// assertNotNull(mTampaRegion.getOpen311Servers()); +// +// // Read the open311 preferences from the region and set +// if (mTampaRegion.getOpen311Servers() != null) { +// for (ObaRegion.Open311Server open311Server : mTampaRegion.getOpen311Servers()) { +// String jurisdictionId = open311Server.getJuridisctionId(); +// +// Open311Option option = new Open311Option(open311Server.getBaseUrl(), +// open311Server.getApiKey(), +// TextUtils.isEmpty(jurisdictionId) ? null : jurisdictionId); +// Open311Manager.initOpen311WithOption(option); +// } +// } +// } - // There should only be one arrival times (trip) request type, because we treat that differently (show arrivals to pick from) - assertTrue(countDynamicTrip == 1); - } +// /** +// * Tests locations in Hillsborough County for services at that location. There should be at +// * least +// * ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD services marked as transit services, as HART +// * is the primary SeeClickFix account holder and therefore all services are transit-related. +// * As of Dec. 2, 2016 services are heuristically matched based on text in the service name +// * (SeeClickFix does not support the group or keyword Open311 elements for explicit matching). +// */ +// @Test +// public void testHillsboroughCounty() { +// List locations = new ArrayList<>(); +// +// // USF area +// locations.add(LocationUtils.makeLocation(28.0612088, -82.415747)); +// // Downtown +// locations.add(LocationUtils.makeLocation(27.9577463, -82.4559472)); +// // Brandon +// locations.add(LocationUtils.makeLocation(27.9520925, -82.3039963)); +// +// List serviceList = _testOpen311AtLocation(locations); +// +// // Make sure we get a valid response here - a failure could be intermittent network issues +// assertNotNull(serviceList); +// +// // Mark the services that are transit-related +// boolean mIsAllTransitHeuristicMatch = ServiceUtils +// .markTransitServices(getTargetContext(), serviceList); +// assertTrue(mIsAllTransitHeuristicMatch); +// +// int countGroupTransit = 0; +// int countDynamicStop = 0; +// int countDynamicTrip = 0; +// +// for (Service s : serviceList) { +// if (s.getGroup().equals(ReportConstants.ISSUE_GROUP_TRANSIT)) { +// countGroupTransit++; +// } +// if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP)) { +// countDynamicStop++; +// } +// if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP)) { +// countDynamicTrip++; +// } +// } +// +// // We should be over the threshold of assuming that all services (request types) are transit-related +// assertTrue(countGroupTransit >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +// +// // Everything not arrival times related should be marked as dynamic stop +// assertTrue(countDynamicStop >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +// +// // There should only be one arrival times (trip) request type, because we treat that differently (show arrivals to pick from) +// assertTrue(countDynamicTrip == 1); +// } // TODO: Re-enable this test. I have disabled this as of December 16, 2023 because the behavior // that worked in December 2016 is no longer functioning as expected. Figure out if this can @@ -198,38 +199,38 @@ public void testHillsboroughCounty() { // assertTrue(countDynamicTrip == 1); // } - private List _testOpen311AtLocation(List locations) { - for (Location l : locations) { - ServiceListRequest slr = new ServiceListRequest(l.getLatitude(), l.getLongitude()); - List open311List = Open311Manager.getAllOpen311(); - ServiceListTask.Callback callback = new ServiceListTask.Callback() { - @Override - public void onServicesTaskCompleted(ServiceListResponse services, Open311 open311) { - } - }; - - ServiceListTask serviceListTask = new ServiceListTask(slr, open311List, callback); - - try { - // Execute the AsyncTask synchronously - ServiceListResponse services = serviceListTask.execute().get(); - List serviceList = new ArrayList<>(); - - // Add services to list if service response is successful - if (services != null && services.isSuccess() && - Open311Manager.isAreaManagedByOpen311(services.getServiceList())) { - for (Service s : services.getServiceList()) { - if (s.getService_name() != null && s.getService_code() != null) { - serviceList.add(s); - } - } - } - return serviceList; - } catch (InterruptedException | ExecutionException e) { - // Print any network errors - e.printStackTrace(); - } - } - return null; - } -} +//// private List _testOpen311AtLocation(List locations) { +//// for (Location l : locations) { +//// ServiceListRequest slr = new ServiceListRequest(l.getLatitude(), l.getLongitude()); +//// List open311List = Open311Manager.getAllOpen311(); +//// ServiceListTask.Callback callback = new ServiceListTask.Callback() { +//// @Override +//// public void onServicesTaskCompleted(ServiceListResponse services, Open311 open311) { +//// } +//// }; +//// +//// ServiceListTask serviceListTask = new ServiceListTask(slr, open311List, callback); +//// +//// try { +//// // Execute the AsyncTask synchronously +//// ServiceListResponse services = serviceListTask.execute().get(); +//// List serviceList = new ArrayList<>(); +//// +//// // Add services to list if service response is successful +//// if (services != null && services.isSuccess() && +//// Open311Manager.isAreaManagedByOpen311(services.getServiceList())) { +//// for (Service s : services.getServiceList()) { +//// if (s.getService_name() != null && s.getService_code() != null) { +//// serviceList.add(s); +//// } +//// } +//// } +//// return serviceList; +//// } catch (InterruptedException | ExecutionException e) { +//// // Print any network errors +//// e.printStackTrace(); +//// } +//// } +//// return null; +//// } +//} From 0da0ced8a06393578df94b8d5ea412627380729a Mon Sep 17 00:00:00 2001 From: Vidit Pawar <116160641+viditpawar0@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:58:01 +0530 Subject: [PATCH 8/8] fixed #981 (#1285) * fixed #981 * fixed #981 - renamed variables and enhanced code structure for readability * fixed #981 - fixed address input getting reset bug * fixed #981 - asked user for trip confirmation after selecting the to address * fixed #981 - asked user for trip confirmation after selecting the to address * fix: trip plan ui (reset time) Signed-off-by: Amr Hossam * refactor picking address Signed-off-by: Amr Hossam * Disable open311 test Signed-off-by: Amr Hossam --------- Signed-off-by: Amr Hossam Co-authored-by: ArctikCircle Co-authored-by: Amr Hossam --- .../io/test/ReportProblemOpen311Test.java | 253 ++++++++-------- .../android/ui/TripPlanFragment.java | 118 ++++++++ .../drawable/baseline_import_contacts_24.xml | 5 + .../main/res/layout/fragment_trip_plan.xml | 271 +++++++++--------- .../src/main/res/values/strings.xml | 2 + 5 files changed, 393 insertions(+), 256 deletions(-) create mode 100644 onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml diff --git a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java index e0dde13eb..d6efa0b56 100644 --- a/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java +++ b/onebusaway-android/src/androidTest/java/org/onebusaway/android/io/test/ReportProblemOpen311Test.java @@ -16,14 +16,10 @@ package org.onebusaway.android.io.test; import org.junit.Before; -import org.junit.Test; import org.junit.runner.RunWith; import org.onebusaway.android.io.elements.ObaRegion; import org.onebusaway.android.mock.MockRegion; import org.onebusaway.android.report.connection.ServiceListTask; -import org.onebusaway.android.report.constants.ReportConstants; -import org.onebusaway.android.report.ui.util.ServiceUtils; -import org.onebusaway.android.util.LocationUtils; import android.location.Location; import android.text.TextUtils; @@ -45,97 +41,102 @@ import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; -/** - * Tests to evaluate interactions with Open311 system for regions that use Open311. - * - * NOTE: These tests make actual HTTP requests to live Open311 servers (SeeClickFix), because we - * make some assumptions required for text heuristic matching to identify transit-related services. - * If there are changes in the live server (e.g., new services added than aren't transit-related - * but include some of the text we're using to identify transit services), these could break our - * assumptions, and we want to know about that. +/* + TODO: Fix me, this test is disabled as of December 25, 2024, due to undefined behavior. Please refer to the associated ticket for more information. + https://github.com/OneBusAway/onebusaway-android/issues/1289. */ -@RunWith(AndroidJUnit4.class) -public class ReportProblemOpen311Test { - - // Mock region to use in tests - ObaRegion mTampaRegion; - - @Before - public void before() { - mTampaRegion = MockRegion.getTampa(getTargetContext()); - - // Clear all open311 endpoints - Open311Manager.clearOpen311(); - - assertNotNull(mTampaRegion.getOpen311Servers()); - - // Read the open311 preferences from the region and set - if (mTampaRegion.getOpen311Servers() != null) { - for (ObaRegion.Open311Server open311Server : mTampaRegion.getOpen311Servers()) { - String jurisdictionId = open311Server.getJuridisctionId(); - - Open311Option option = new Open311Option(open311Server.getBaseUrl(), - open311Server.getApiKey(), - TextUtils.isEmpty(jurisdictionId) ? null : jurisdictionId); - Open311Manager.initOpen311WithOption(option); - } - } - } - - /** - * Tests locations in Hillsborough County for services at that location. There should be at - * least - * ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD services marked as transit services, as HART - * is the primary SeeClickFix account holder and therefore all services are transit-related. - * As of Dec. 2, 2016 services are heuristically matched based on text in the service name - * (SeeClickFix does not support the group or keyword Open311 elements for explicit matching). - */ - @Test - public void testHillsboroughCounty() { - List locations = new ArrayList<>(); - - // USF area - locations.add(LocationUtils.makeLocation(28.0612088, -82.415747)); - // Downtown - locations.add(LocationUtils.makeLocation(27.9577463, -82.4559472)); - // Brandon - locations.add(LocationUtils.makeLocation(27.9520925, -82.3039963)); - - List serviceList = _testOpen311AtLocation(locations); - - // Make sure we get a valid response here - a failure could be intermittent network issues - assertNotNull(serviceList); - - // Mark the services that are transit-related - boolean mIsAllTransitHeuristicMatch = ServiceUtils - .markTransitServices(getTargetContext(), serviceList); - assertTrue(mIsAllTransitHeuristicMatch); - - int countGroupTransit = 0; - int countDynamicStop = 0; - int countDynamicTrip = 0; - - for (Service s : serviceList) { - if (s.getGroup().equals(ReportConstants.ISSUE_GROUP_TRANSIT)) { - countGroupTransit++; - } - if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP)) { - countDynamicStop++; - } - if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP)) { - countDynamicTrip++; - } - } - // We should be over the threshold of assuming that all services (request types) are transit-related - assertTrue(countGroupTransit >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +///** +// * Tests to evaluate interactions with Open311 system for regions that use Open311. +// * +// * NOTE: These tests make actual HTTP requests to live Open311 servers (SeeClickFix), because we +// * make some assumptions required for text heuristic matching to identify transit-related services. +// * If there are changes in the live server (e.g., new services added than aren't transit-related +// * but include some of the text we're using to identify transit services), these could break our +// * assumptions, and we want to know about that. +// */ +//@RunWith(AndroidJUnit4.class) +//public class ReportProblemOpen311Test { - // Everything not arrival times related should be marked as dynamic stop - assertTrue(countDynamicStop >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); + // Mock region to use in tests +// ObaRegion mTampaRegion; +// +// @Before +// public void before() { +// mTampaRegion = MockRegion.getTampa(getTargetContext()); +// +// // Clear all open311 endpoints +// Open311Manager.clearOpen311(); +// +// assertNotNull(mTampaRegion.getOpen311Servers()); +// +// // Read the open311 preferences from the region and set +// if (mTampaRegion.getOpen311Servers() != null) { +// for (ObaRegion.Open311Server open311Server : mTampaRegion.getOpen311Servers()) { +// String jurisdictionId = open311Server.getJuridisctionId(); +// +// Open311Option option = new Open311Option(open311Server.getBaseUrl(), +// open311Server.getApiKey(), +// TextUtils.isEmpty(jurisdictionId) ? null : jurisdictionId); +// Open311Manager.initOpen311WithOption(option); +// } +// } +// } - // There should only be one arrival times (trip) request type, because we treat that differently (show arrivals to pick from) - assertTrue(countDynamicTrip == 1); - } +// /** +// * Tests locations in Hillsborough County for services at that location. There should be at +// * least +// * ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD services marked as transit services, as HART +// * is the primary SeeClickFix account holder and therefore all services are transit-related. +// * As of Dec. 2, 2016 services are heuristically matched based on text in the service name +// * (SeeClickFix does not support the group or keyword Open311 elements for explicit matching). +// */ +// @Test +// public void testHillsboroughCounty() { +// List locations = new ArrayList<>(); +// +// // USF area +// locations.add(LocationUtils.makeLocation(28.0612088, -82.415747)); +// // Downtown +// locations.add(LocationUtils.makeLocation(27.9577463, -82.4559472)); +// // Brandon +// locations.add(LocationUtils.makeLocation(27.9520925, -82.3039963)); +// +// List serviceList = _testOpen311AtLocation(locations); +// +// // Make sure we get a valid response here - a failure could be intermittent network issues +// assertNotNull(serviceList); +// +// // Mark the services that are transit-related +// boolean mIsAllTransitHeuristicMatch = ServiceUtils +// .markTransitServices(getTargetContext(), serviceList); +// assertTrue(mIsAllTransitHeuristicMatch); +// +// int countGroupTransit = 0; +// int countDynamicStop = 0; +// int countDynamicTrip = 0; +// +// for (Service s : serviceList) { +// if (s.getGroup().equals(ReportConstants.ISSUE_GROUP_TRANSIT)) { +// countGroupTransit++; +// } +// if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_STOP)) { +// countDynamicStop++; +// } +// if (s.getType().equals(ReportConstants.DYNAMIC_TRANSIT_SERVICE_TRIP)) { +// countDynamicTrip++; +// } +// } +// +// // We should be over the threshold of assuming that all services (request types) are transit-related +// assertTrue(countGroupTransit >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +// +// // Everything not arrival times related should be marked as dynamic stop +// assertTrue(countDynamicStop >= ReportConstants.NUM_TRANSIT_SERVICES_THRESHOLD); +// +// // There should only be one arrival times (trip) request type, because we treat that differently (show arrivals to pick from) +// assertTrue(countDynamicTrip == 1); +// } // TODO: Re-enable this test. I have disabled this as of December 16, 2023 because the behavior // that worked in December 2016 is no longer functioning as expected. Figure out if this can @@ -198,38 +199,38 @@ public void testHillsboroughCounty() { // assertTrue(countDynamicTrip == 1); // } - private List _testOpen311AtLocation(List locations) { - for (Location l : locations) { - ServiceListRequest slr = new ServiceListRequest(l.getLatitude(), l.getLongitude()); - List open311List = Open311Manager.getAllOpen311(); - ServiceListTask.Callback callback = new ServiceListTask.Callback() { - @Override - public void onServicesTaskCompleted(ServiceListResponse services, Open311 open311) { - } - }; - - ServiceListTask serviceListTask = new ServiceListTask(slr, open311List, callback); - - try { - // Execute the AsyncTask synchronously - ServiceListResponse services = serviceListTask.execute().get(); - List serviceList = new ArrayList<>(); - - // Add services to list if service response is successful - if (services != null && services.isSuccess() && - Open311Manager.isAreaManagedByOpen311(services.getServiceList())) { - for (Service s : services.getServiceList()) { - if (s.getService_name() != null && s.getService_code() != null) { - serviceList.add(s); - } - } - } - return serviceList; - } catch (InterruptedException | ExecutionException e) { - // Print any network errors - e.printStackTrace(); - } - } - return null; - } -} +//// private List _testOpen311AtLocation(List locations) { +//// for (Location l : locations) { +//// ServiceListRequest slr = new ServiceListRequest(l.getLatitude(), l.getLongitude()); +//// List open311List = Open311Manager.getAllOpen311(); +//// ServiceListTask.Callback callback = new ServiceListTask.Callback() { +//// @Override +//// public void onServicesTaskCompleted(ServiceListResponse services, Open311 open311) { +//// } +//// }; +//// +//// ServiceListTask serviceListTask = new ServiceListTask(slr, open311List, callback); +//// +//// try { +//// // Execute the AsyncTask synchronously +//// ServiceListResponse services = serviceListTask.execute().get(); +//// List serviceList = new ArrayList<>(); +//// +//// // Add services to list if service response is successful +//// if (services != null && services.isSuccess() && +//// Open311Manager.isAreaManagedByOpen311(services.getServiceList())) { +//// for (Service s : services.getServiceList()) { +//// if (s.getService_name() != null && s.getService_code() != null) { +//// serviceList.add(s); +//// } +//// } +//// } +//// return serviceList; +//// } catch (InterruptedException | ExecutionException e) { +//// // Print any network errors +//// e.printStackTrace(); +//// } +//// } +//// return null; +//// } +//} diff --git a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java index edc42cb79..2b408cfd3 100644 --- a/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java +++ b/onebusaway-android/src/main/java/org/onebusaway/android/ui/TripPlanFragment.java @@ -22,8 +22,11 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.res.TypedArray; +import android.database.Cursor; import android.location.Location; +import android.net.Uri; import android.os.Bundle; +import android.provider.ContactsContract; import android.text.TextUtils; import android.util.Log; import android.view.ContextThemeWrapper; @@ -46,6 +49,11 @@ import android.widget.TimePicker; import android.widget.Toast; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; @@ -84,6 +92,9 @@ public class TripPlanFragment extends Fragment { + private String fromAddress; + private String toAddress; + /** * Allows calling activity to register to know when to send request. */ @@ -104,6 +115,8 @@ interface Listener { private AutoCompleteTextView mToAddressTextArea; private ImageButton mFromCurrentLocationImageButton; private ImageButton mToCurrentLocationImageButton; + private ImageButton mfromContactsImageButton; + private ImageButton mToContactsImageButton; private Spinner mDate; private ArrayAdapter mDateAdapter; private Spinner mTime; @@ -127,6 +140,87 @@ interface Listener { private FirebaseAnalytics mFirebaseAnalytics; + // Updates the Address Input field with the formatted address selected by the user from their contacts. + private final String ADDRESS_INPUT_ID_KEY = "addressInputId"; + private final ActivityResultContract selectAddressFromContactContract = new ActivityResultContract() { + private int addressInputId; + + @NonNull + @Override + public Intent createIntent(@NonNull Context context, TextView addressInput) { + Intent pickContactIntent = new Intent(Intent.ACTION_PICK); + pickContactIntent.setType(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_TYPE); + addressInputId = addressInput.getId(); + return pickContactIntent; + } + + @Override + public Intent parseResult(int i, @Nullable Intent addressIntent) { + if (addressIntent != null) { + return addressIntent.putExtra(ADDRESS_INPUT_ID_KEY, addressInputId); + } + return null; + } + }; + + private final ActivityResultCallback addressIntentActivityResultCallback = addressIntent -> { + if (addressIntent == null) { + return; + } + + Uri addressUri = addressIntent.getData(); + if (addressUri == null) { + return; + } + + String[] projection = {ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS}; + + try (Cursor cursor = getContext().getContentResolver().query(addressUri, projection, null, null, null)) { + if (cursor == null || !cursor.moveToFirst()) { + return; + } + + String address = extractAddress(cursor); + int addressInputId = addressIntent.getIntExtra(ADDRESS_INPUT_ID_KEY, -1); + if (addressInputId == -1) { + return; + } + + updateAddressInput(address, addressInputId); + updateAddressData(address, addressInputId); + } + }; + + private String extractAddress(Cursor cursor) { + int addressIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS); + return cursor.getString(addressIndex).replace("\n", ", "); + } + + private void updateAddressInput(String address, int addressInputId) { + TextView addressInput = getActivity().findViewById(addressInputId); + addressInput.post(() -> addressInput.setText(address)); + addressInput.requestFocus(); + } + + private void updateAddressData(String address, int addressInputId) { + CustomAddress customAddress = CustomAddress.getEmptyAddress(); + customAddress.setAddressLine(0, address); + + if (addressInputId == mFromAddressTextArea.getId()) { + mFromAddress = customAddress; + mBuilder.setFrom(mFromAddress); + } else if (addressInputId == mToAddressTextArea.getId()) { + mToAddress = customAddress; + mBuilder.setTo(mToAddress); + } + } + + + private final ActivityResultLauncher mSelectAddressFromContactLauncher = registerForActivityResult( + selectAddressFromContactContract, + addressIntentActivityResultCallback + ); + // Create view, initialize state @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -152,6 +246,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa mToAddressTextArea = (AutoCompleteTextView) view.findViewById(R.id.toAddressTextArea); mFromCurrentLocationImageButton = (ImageButton) view.findViewById(R.id.fromCurrentLocationImageButton); mToCurrentLocationImageButton = (ImageButton) view.findViewById(R.id.toCurrentLocationImageButton); + mfromContactsImageButton = view.findViewById(R.id.fromContactsImageButton); + mToContactsImageButton = view.findViewById(R.id.toContactsImageButton); mDate = (Spinner) view.findViewById(R.id.date); mDateAdapter = new ArrayAdapter(getActivity(), R.layout.simple_list_item); mDate.setAdapter(mDateAdapter); @@ -256,6 +352,10 @@ public void onClick(View v) { } }); + mToContactsImageButton.setOnClickListener(v -> mSelectAddressFromContactLauncher.launch(mToAddressTextArea)); + + mfromContactsImageButton.setOnClickListener(v -> mSelectAddressFromContactLauncher.launch(mFromAddressTextArea)); + // Start: default from address is Current Location, to address is unset return view; } @@ -300,6 +400,8 @@ private void checkRequestAndSubmit() { if (mBuilder.ready() && mListener != null) { mFromAddressTextArea.dismissDropDown(); mToAddressTextArea.dismissDropDown(); + mFromAddressTextArea.clearFocus(); + mToAddressTextArea.clearFocus(); UIUtils.closeKeyboard(getContext(), mFromAddressTextArea); mListener.onTripRequestReady(); } @@ -376,6 +478,22 @@ public void onNothingSelected(AdapterView parent) { if (BuildConfig.USE_PELIAS_GEOCODING) { showTutorial(ShowcaseViewUtils.TUTORIAL_TRIP_PLAN_GEOCODER, (AppCompatActivity) getActivity(), null, true); } + + if (fromAddress != null) { + mFromAddressTextArea.setText(fromAddress); + } + if (toAddress != null) { + mToAddressTextArea.setText(toAddress); + } + } + + + + @Override + public void onPause() { + super.onPause(); + fromAddress = mFromAddressTextArea.getText().toString(); + toAddress = mToAddressTextArea.getText().toString(); } @Override diff --git a/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml b/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml new file mode 100644 index 000000000..bbd37209a --- /dev/null +++ b/onebusaway-android/src/main/res/drawable/baseline_import_contacts_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml b/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml index fbed6437f..b27625f42 100755 --- a/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml +++ b/onebusaway-android/src/main/res/layout/fragment_trip_plan.xml @@ -21,174 +21,185 @@ android:layout_margin="16dp"> - - - + android:layout_height="wrap_content"> - + android:layout_toLeftOf="@id/fromContactsImageButton" + android:layout_toStartOf="@id/fromContactsImageButton" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + app:endIconMode="clear_text"> + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:id="@+id/fromContactsImageButton" + android:background="#00000000" + android:src="@drawable/baseline_import_contacts_24" + app:tint="@color/material_gray" + android:layout_gravity="center_vertical" + android:layout_toLeftOf="@id/fromCurrentLocationImageButton" + android:layout_centerVertical="true" + android:contentDescription="@string/set_destination_to_my_location" /> + + + - - + android:layout_below="@id/trip_plan_from_layout"> - + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_toLeftOf="@id/toContactsImageButton" + android:layout_toStartOf="@id/toContactsImageButton" + android:layout_centerVertical="true" + app:endIconMode="clear_text"> + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginStart="5dp" + android:id="@+id/toContactsImageButton" + android:background="#00000000" + android:src="@drawable/baseline_import_contacts_24" + app:tint="@color/material_gray" + android:layout_gravity="center_vertical" + android:layout_toLeftOf="@id/toCurrentLocationImageButton" + android:layout_centerVertical="true" + android:contentDescription="@string/set_destination_to_my_location" /> + + + android:id="@+id/time_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/to_and_from_layout" + android:orientation="horizontal" + android:paddingTop="8dp"> + android:id="@+id/leavingChoiceSpinner" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" + tools:text="Leaving" /> - - - + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/date" + tools:text="June 14" + android:inputType="none" + android:focusable="false" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:color="@color/trip_plan_label" + android:text="@string/trip_plan_stop_connector" + android:layout_gravity="center_vertical" + android:paddingEnd="8dp" /> - + android:id="@+id/time" + android:layout_width="0dp" + android:layout_height="wrap_content" + tools:text="04:01 pm" + android:layout_weight="1" + android:inputType="none" + android:focusable="false" + android:layout_gravity="center_vertical" + android:textAppearance="?android:attr/textAppearanceSmall" /> - + android:layout_width="24dp" + android:layout_height="24dp" + android:scaleType="fitXY" + android:id="@+id/resetTimeImageButton" + android:src="@drawable/ic_arrival_time" + android:background="#00000000" + android:layout_gravity="center_vertical" + android:contentDescription="@string/reset_time" + app:tint="@color/material_gray" /> diff --git a/onebusaway-android/src/main/res/values/strings.xml b/onebusaway-android/src/main/res/values/strings.xml index dfc8cdfbc..9258fbc57 100644 --- a/onebusaway-android/src/main/res/values/strings.xml +++ b/onebusaway-android/src/main/res/values/strings.xml @@ -1278,4 +1278,6 @@ More Info Display test alerts Display test-wide alerts for regions + Do you want to plan the trip now? + Plan Trip?