Standardize filenames for logcat and bugreport. (#635)

diff --git a/mobly/controllers/android_device.py b/mobly/controllers/android_device.py
index 97d80cc..1080078 100644
--- a/mobly/controllers/android_device.py
+++ b/mobly/controllers/android_device.py
@@ -960,8 +960,6 @@
 
         Args:
             test_name: Name of the test method that triggered this bug report.
-                If not set, then this will default to
-                android_device.DEFAULT_BUG_REPORT_NAME.
             begin_time: Timestamp of when the test started. If not set, then
                 this will default to the current time.
             timeout: float, the number of seconds to wait for bugreport to
@@ -970,11 +968,11 @@
                 should be saved.
 
         Returns:
-          A string containing the absolute path to the bug report on the host
-          machine.
+            A string that is the absolute path to the bug report on the host.
         """
-        if test_name is None:
-            test_name = DEFAULT_BUG_REPORT_NAME
+        prefix = DEFAULT_BUG_REPORT_NAME
+        if test_name:
+            prefix = '%s,%s' % (DEFAULT_BUG_REPORT_NAME, test_name)
         if begin_time is None:
             begin_time = mobly_logger.get_log_file_timestamp()
 
@@ -987,20 +985,18 @@
                 new_br = False
         except adb.AdbError:
             new_br = False
-        if destination:
-            br_path = utils.abs_path(destination)
-        else:
-            br_path = os.path.join(self.log_path, 'BugReports')
+
+        if destination is None:
+            destination = os.path.join(self.log_path, 'BugReports')
+        br_path = utils.abs_path(destination)
         utils.create_dir(br_path)
-        base_name = ',%s,%s.txt' % (begin_time, self._normalized_serial)
+        filename = self.generate_filename(prefix, begin_time, 'txt')
         if new_br:
-            base_name = base_name.replace('.txt', '.zip')
-        test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
-        out_name = test_name[:test_name_len] + base_name
-        full_out_path = os.path.join(br_path, out_name.replace(' ', r'\ '))
+            filename = filename.replace('.txt', '.zip')
+        full_out_path = os.path.join(br_path, filename)
         # in case device restarted, wait for adb interface to return
         self.wait_for_boot_completion()
-        self.log.info('Taking bugreport for %s.', test_name)
+        self.log.debug('Start taking bugreport.')
         if new_br:
             out = self.adb.shell('bugreportz', timeout=timeout).decode('utf-8')
             if not out.startswith('OK'):
@@ -1013,8 +1009,7 @@
             self.adb.bugreport(' > "%s"' % full_out_path,
                                shell=True,
                                timeout=timeout)
-        self.log.info('Bugreport for %s taken at %s.', test_name,
-                      full_out_path)
+        self.log.debug('Bugreport taken at %s.', full_out_path)
         return full_out_path
 
     def run_iperf_client(self, server_host, extra_args=''):
diff --git a/mobly/controllers/android_device_lib/services/logcat.py b/mobly/controllers/android_device_lib/services/logcat.py
index c79b89f..2582750 100644
--- a/mobly/controllers/android_device_lib/services/logcat.py
+++ b/mobly/controllers/android_device_lib/services/logcat.py
@@ -101,7 +101,7 @@
     def create_per_test_excerpt(self, current_test_info):
         """Convenient method for creating excerpts of adb logcat.
 
-        .. deprecated:: 1.9.2
+        .. deprecated:: 1.10
            Use :func:`create_output_excerpts` instead.
 
         To use this feature, call this method at the end of: `setup_class`,
@@ -162,10 +162,16 @@
         """Takes an excerpt of the adb logcat log from a certain time point to
         current time.
 
+        .. deprecated:: 1.10
+            Use :func:`create_output_excerpts` instead.
+
         Args:
             tag: An identifier of the time period, usualy the name of a test.
             begin_time: Logline format timestamp of the beginning of the time
                 period.
+
+        Returns:
+            String, full path to the excerpt file created.
         """
         if not self.adb_logcat_file_path:
             raise Error(
@@ -175,13 +181,8 @@
         self._ad.log.debug('Extracting adb log from logcat.')
         adb_excerpt_path = os.path.join(self._ad.log_path, 'AdbLogExcerpts')
         utils.create_dir(adb_excerpt_path)
-        f_name = os.path.basename(self.adb_logcat_file_path)
-        out_name = f_name.replace('adblog,', '').replace('.txt', '')
-        out_name = ',%s,%s.txt' % (begin_time, out_name)
-        out_name = out_name.replace(':', '-')
-        tag_len = utils.MAX_FILENAME_LEN - len(out_name)
-        tag = tag[:tag_len]
-        out_name = tag + out_name
+        out_name = '%s,%s.txt' % (tag, begin_time)
+        out_name = mobly_logger.sanitize_filename(out_name)
         full_adblog_path = os.path.join(adb_excerpt_path, out_name)
         with io.open(full_adblog_path, 'w', encoding='utf-8') as out:
             in_file = self.adb_logcat_file_path
@@ -208,6 +209,7 @@
                     else:
                         if in_range:
                             break
+        return full_adblog_path
 
     def _assert_not_running(self):
         """Asserts the logcat service is not running.
@@ -252,8 +254,8 @@
         self._enable_logpersist()
         logcat_file_path = self._config.output_file_path
         if not logcat_file_path:
-            f_name = 'adblog,%s,%s.txt' % (self._ad.model,
-                                           self._ad._normalized_serial)
+            f_name = self._ad.generate_filename(self.OUTPUT_FILE_TYPE,
+                                                extension_name='txt')
             logcat_file_path = os.path.join(self._ad.log_path, f_name)
         utils.create_dir(os.path.dirname(logcat_file_path))
         cmd = '"%s" -s %s logcat -v threadtime %s >> "%s"' % (
diff --git a/tests/lib/mock_android_device.py b/tests/lib/mock_android_device.py
index 28c90e6..e6804e7 100755
--- a/tests/lib/mock_android_device.py
+++ b/tests/lib/mock_android_device.py
@@ -78,6 +78,7 @@
 
 class MockAdbProxy(object):
     """Mock class that swaps out calls to adb with mock calls."""
+
     def __init__(self,
                  serial='',
                  fail_br=False,
@@ -138,9 +139,9 @@
         return self.mock_properties
 
     def bugreport(self, args, shell=False, timeout=None):
-        expected = os.path.join(logging.log_path,
-                                'AndroidDevice%s' % self.serial, 'BugReports',
-                                'test_something,sometime,%s' % self.serial)
+        expected = os.path.join(
+            logging.log_path, 'AndroidDevice%s' % self.serial, 'BugReports',
+            'bugreport,test_something,%s,fakemodel,sometime' % self.serial)
         if expected not in args:
             raise Error('"Expected "%s", got "%s"' % (expected, args))
 
@@ -148,6 +149,7 @@
         """All calls to the none-existent functions in adb proxy would
         simply return the adb command string.
         """
+
         def adb_call(*args, **kwargs):
             arg_str = ' '.join(str(elem) for elem in args)
             return arg_str
@@ -157,6 +159,7 @@
 
 class MockFastbootProxy(object):
     """Mock class that swaps out calls to adb with mock calls."""
+
     def __init__(self, serial):
         self.serial = serial
 
diff --git a/tests/mobly/controllers/android_device_lib/services/logcat_test.py b/tests/mobly/controllers/android_device_lib/services/logcat_test.py
index 94416d2..7b2217d 100755
--- a/tests/mobly/controllers/android_device_lib/services/logcat_test.py
+++ b/tests/mobly/controllers/android_device_lib/services/logcat_test.py
@@ -97,21 +97,24 @@
     @mock.patch('mobly.utils.start_standing_subprocess',
                 return_value='process')
     @mock.patch('mobly.utils.stop_standing_subprocess')
-    def test_start_and_stop(self, stop_proc_mock, start_proc_mock,
-                            create_dir_mock, FastbootProxy, MockAdbProxy):
+    @mock.patch('mobly.logger.get_log_file_timestamp')
+    def test_start_and_stop(self, get_timestamp_mock, stop_proc_mock,
+                            start_proc_mock, create_dir_mock, FastbootProxy,
+                            MockAdbProxy):
         """Verifies the steps of collecting adb logcat on an AndroidDevice
         object, including various function calls and the expected behaviors of
         the calls.
         """
         mock_serial = '1'
+        get_timestamp_mock.return_value = '123'
         ad = android_device.AndroidDevice(serial=mock_serial)
         logcat_service = logcat.Logcat(ad)
         logcat_service.start()
         # Verify start did the correct operations.
         self.assertTrue(logcat_service._adb_logcat_process)
-        expected_log_path = os.path.join(logging.log_path,
-                                         'AndroidDevice%s' % ad.serial,
-                                         'adblog,fakemodel,%s.txt' % ad.serial)
+        expected_log_path = os.path.join(
+            logging.log_path, 'AndroidDevice%s' % ad.serial,
+            'logcat,%s,fakemodel,123.txt' % ad.serial)
         create_dir_mock.assert_called_with(os.path.dirname(expected_log_path))
         adb_cmd = '"adb" -s %s logcat -v threadtime  >> %s'
         start_proc_mock.assert_called_with(
@@ -322,14 +325,17 @@
     @mock.patch('mobly.utils.start_standing_subprocess',
                 return_value='process')
     @mock.patch('mobly.utils.stop_standing_subprocess')
-    def test_take_logcat_with_extra_params(self, stop_proc_mock,
-                                           start_proc_mock, create_dir_mock,
-                                           FastbootProxy, MockAdbProxy):
+    @mock.patch('mobly.logger.get_log_file_timestamp')
+    def test_take_logcat_with_extra_params(self, get_timestamp_mock,
+                                           stop_proc_mock, start_proc_mock,
+                                           create_dir_mock, FastbootProxy,
+                                           MockAdbProxy):
         """Verifies the steps of collecting adb logcat on an AndroidDevice
         object, including various function calls and the expected behaviors of
         the calls.
         """
         mock_serial = '1'
+        get_timestamp_mock.return_value = '123'
         ad = android_device.AndroidDevice(serial=mock_serial)
         configs = logcat.Config()
         configs.logcat_params = '-b radio'
@@ -337,9 +343,9 @@
         logcat_service.start()
         # Verify start did the correct operations.
         self.assertTrue(logcat_service._adb_logcat_process)
-        expected_log_path = os.path.join(logging.log_path,
-                                         'AndroidDevice%s' % ad.serial,
-                                         'adblog,fakemodel,%s.txt' % ad.serial)
+        expected_log_path = os.path.join(
+            logging.log_path, 'AndroidDevice%s' % ad.serial,
+            'logcat,%s,fakemodel,123.txt' % ad.serial)
         create_dir_mock.assert_called_with(os.path.dirname(expected_log_path))
         adb_cmd = '"adb" -s %s logcat -v threadtime -b radio >> %s'
         start_proc_mock.assert_called_with(
@@ -389,14 +395,11 @@
             logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
         logcat_service.start()
         utils.create_dir(ad.log_path)
-        mock_adb_log_path = os.path.join(
-            ad.log_path, 'adblog,%s,%s.txt' % (ad.model, ad.serial))
+        mock_adb_log_path = logcat_service.adb_logcat_file_path
         with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f:
             f.write(MOCK_ADB_LOGCAT)
-        logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
-        cat_file_path = os.path.join(
-            ad.log_path, 'AdbLogExcerpts',
-            ('some_test,02-29 14-02-20.123,%s,%s.txt') % (ad.model, ad.serial))
+        cat_file_path = logcat_service.cat_adb_log('some_test',
+                                                   MOCK_ADB_LOGCAT_BEGIN_TIME)
         with io.open(cat_file_path, 'r', encoding='utf-8') as f:
             actual_cat = f.read()
         self.assertEqual(actual_cat, ''.join(MOCK_ADB_LOGCAT_CAT_RESULT))
@@ -432,14 +435,11 @@
             logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
         logcat_service.start()
         utils.create_dir(ad.log_path)
-        mock_adb_log_path = os.path.join(
-            ad.log_path, 'adblog,%s,%s.txt' % (ad.model, ad.serial))
+        mock_adb_log_path = logcat_service.adb_logcat_file_path
         with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f:
             f.write(MOCK_ADB_UNICODE_LOGCAT)
-        logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
-        cat_file_path = os.path.join(
-            ad.log_path, 'AdbLogExcerpts',
-            ('some_test,02-29 14-02-20.123,%s,%s.txt') % (ad.model, ad.serial))
+        cat_file_path = logcat_service.cat_adb_log('some_test',
+                                                   MOCK_ADB_LOGCAT_BEGIN_TIME)
         with io.open(cat_file_path, 'r', encoding='utf-8') as f:
             actual_cat = f.read()
         self.assertEqual(actual_cat,
diff --git a/tests/mobly/controllers/android_device_test.py b/tests/mobly/controllers/android_device_test.py
index 91381ab..1e5c1f1 100755
--- a/tests/mobly/controllers/android_device_test.py
+++ b/tests/mobly/controllers/android_device_test.py
@@ -588,7 +588,8 @@
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
             output_path,
-            os.path.join(expected_path, 'test_something,sometime,1.zip'))
+            os.path.join(expected_path,
+                         'bugreport,test_something,1,fakemodel,sometime.zip'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy('1',
@@ -627,7 +628,7 @@
         self.assertEqual(
             output_path,
             os.path.join(expected_path,
-                         'bugreport,07-22-2019_17-53-34-450,1.zip'))
+                         'bugreport,1,fakemodel,07-22-2019_17-53-34-450.zip'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy('1'))
@@ -648,8 +649,10 @@
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
             output_path,
-            os.path.join(expected_path,
-                         'test_something,07-22-2019_17-53-34-450,1.zip'))
+            os.path.join(
+                expected_path,
+                'bugreport,test_something,1,fakemodel,07-22-2019_17-53-34-450.zip'
+            ))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy(1))
@@ -666,8 +669,8 @@
                                      'BugReports')
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
-            output_path, os.path.join(expected_path,
-                                      'bugreport,sometime,1.zip'))
+            output_path,
+            os.path.join(expected_path, 'bugreport,1,fakemodel,sometime.zip'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy(1))
@@ -685,7 +688,8 @@
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
             output_path,
-            os.path.join(expected_path, 'test_something,sometime,1.zip'))
+            os.path.join(expected_path,
+                         'bugreport,test_something,1,fakemodel,sometime.zip'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy('1'))
@@ -704,7 +708,8 @@
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
             output_path,
-            os.path.join(expected_path, 'test_something,sometime,1.zip'))
+            os.path.join(expected_path,
+                         'bugreport,test_something,1,fakemodel,sometime.zip'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy(
@@ -728,7 +733,8 @@
         create_dir_mock.assert_called_with(expected_path)
         self.assertEqual(
             output_path,
-            os.path.join(expected_path, 'test_something,sometime,1.txt'))
+            os.path.join(expected_path,
+                         'bugreport,test_something,1,fakemodel,sometime.txt'))
 
     @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy',
                 return_value=mock_android_device.MockAdbProxy('1'))