Loading core/java/android/print/PrintAttributes.java +9 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import java.util.Map; */ public final class PrintAttributes implements Parcelable { /** @hide */ // LINT.IfChange @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "COLOR_MODE_" }, value = { COLOR_MODE_MONOCHROME, Loading @@ -62,9 +63,12 @@ public final class PrintAttributes implements Parcelable { private static final int VALID_COLOR_MODES = COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR; // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) /** @hide */ @Retention(RetentionPolicy.SOURCE) // LINT.IfChange @IntDef(flag = true, prefix = { "DUPLEX_MODE_" }, value = { DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, Loading @@ -81,6 +85,8 @@ public final class PrintAttributes implements Parcelable { private static final int VALID_DUPLEX_MODES = DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE; // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) private @Nullable MediaSize mMediaSize; private @Nullable Resolution mResolution; Loading Loading @@ -462,6 +468,7 @@ public final class PrintAttributes implements Parcelable { private static final Map<String, MediaSize> sIdToMediaSizeMap = new ArrayMap<>(); // LINT.IfChange /** * Unknown media size in portrait mode. * <p> Loading Loading @@ -840,6 +847,8 @@ public final class PrintAttributes implements Parcelable { public static final @NonNull MediaSize JPN_OE_PHOTO_L = new MediaSize("JPN_OE_PHOTO_L", "android", R.string.mediasize_japanese_l, 3500, 5000); // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) private final @NonNull String mId; /**@hide */ Loading packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt +594 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/PrintSpooler/src/com/android/printspooler/stats/StatsLogWrapper.kt +19 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,23 @@ open class StatsLogWrapper { printServiceCount, ) } open fun internalPrinterDiscovery( @UserIdInt printServiceId: Int, supportedColors: Set<StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent>, supportedSizes: Set<StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent>, supportedDuplexModes: Set<StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent>, ) { val colorBits = supportedColors.map { it.rawValue }.toIntArray() val mediaSizes = supportedSizes.map { it.rawValue }.toIntArray() val duplexModes = supportedDuplexModes.map { it.rawValue }.toIntArray() PrintSpoolerStatsLog.write( PrintSpoolerStatsLog.FRAMEWORK_PRINTER_DISCOVERY, printServiceId, colorBits, mediaSizes, duplexModes, ) } } packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +25 −0 Original line number Diff line number Diff line Loading @@ -2663,6 +2663,31 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } } if (Flags.printingTelemetry()) { for (final PrinterInfo printer : newPrintersMap.values()) { final PrinterCapabilitiesInfo caps = printer.getCapabilities(); int colorModesMask = 0; int duplexModesMask = 0; Set<MediaSize> mediaSizes = new HashSet<>(); if (caps != null) { colorModesMask = caps.getColorModes(); duplexModesMask = caps.getDuplexModes(); mediaSizes = new HashSet<>(caps.getMediaSizes()); } final String serviceName = printer.getId().getServiceName().getPackageName(); try { final int serviceUId = getPackageManager().getApplicationInfo(serviceName, 0).uid; StatsAsyncLogger.INSTANCE .PrinterDiscovery(serviceUId, colorModesMask, duplexModesMask, mediaSizes); } catch (NameNotFoundException e) { Log.e(LOG_TAG, "Failed to get uid for service"); } } } // Add the rest of the new printers, i.e. what is left. addPrinters(newPrinterHolders, newPrintersMap.values()); Loading packages/PrintSpooler/tests/robolectric/src/com/android/printspooler/stats/StatsAsyncLoggerTest.kt +89 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.printspooler.stats import android.os.Handler import android.print.PrintAttributes import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import java.util.concurrent.Semaphore Loading Loading @@ -61,6 +62,90 @@ open class StatsAsyncLoggerTest { StatsAsyncLogger.stopLogging() } @Test fun printerDiscoverySuccessfullyLoggedTest() { val logWrapperInOrder = inOrder(mStatsLogWrapper) val handlerInOrder = inOrder(mHandler) val semaphoreInOrder = inOrder(mSemaphore) val timeCaptor = argumentCaptor<Long>() val runnableCaptor = argumentCaptor<Runnable>() StatsAsyncLogger.startLogging() StatsAsyncLogger.testSetSemaphore(mSemaphore) StatsAsyncLogger.testSetHandler(mHandler) StatsAsyncLogger.testSetStatsLogWrapper(mStatsLogWrapper) // "foo" printer service: Generally arbitrary arguments focusing more on creating non-empty // lists. val printServiceFoo = 42 val colorsMaskFoo = (PrintAttributes.COLOR_MODE_COLOR or PrintAttributes.COLOR_MODE_MONOCHROME) val supportedMediaSizesFoo = setOf<PrintAttributes.MediaSize>( PrintAttributes.MediaSize.NA_LETTER, PrintAttributes.MediaSize.JPN_HAGAKI, ) val duplexModeMaskFoo = (PrintAttributes.DUPLEX_MODE_LONG_EDGE or PrintAttributes.DUPLEX_MODE_SHORT_EDGE) assertThat( StatsAsyncLogger.PrinterDiscovery( printServiceFoo, colorsMaskFoo, duplexModeMaskFoo, supportedMediaSizesFoo, ) ) .isTrue() // "bar" printer service: Generally arbitrary arguments focusing more on empty/default // values. val printServiceBar = 1337 assertThat(StatsAsyncLogger.PrinterDiscovery(printServiceBar, 0, 0, setOf())).isTrue() handlerInOrder .verify(mHandler, times(2)) .postAtTime(runnableCaptor.capture(), timeCaptor.capture()) handlerInOrder.verifyNoMoreInteractions() // Validate delay args val firstTime = timeCaptor.firstValue val secondTime = timeCaptor.secondValue assertThat(secondTime - firstTime) .isAtLeast(StatsAsyncLogger.EVENT_REPORTED_MIN_INTERVAL.inWholeMilliseconds) assertThat(secondTime - firstTime) .isAtMost(2 * StatsAsyncLogger.EVENT_REPORTED_MIN_INTERVAL.inWholeMilliseconds) // Validate Runnable logic runnableCaptor.firstValue.run() runnableCaptor.secondValue.run() logWrapperInOrder .verify(mStatsLogWrapper) .internalPrinterDiscovery( printServiceFoo, setOf( StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent.COLOR, StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent.MONOCHROME, ), setOf( StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent.NA_LETTER, StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent.JPN_HAGAKI, ), setOf( StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent.LONG_EDGE, StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent.SHORT_EDGE, ), ) logWrapperInOrder .verify(mStatsLogWrapper) .internalPrinterDiscovery(printServiceBar, setOf(), setOf(), setOf()) logWrapperInOrder.verifyNoMoreInteractions() // Validate Semaphore logic semaphoreInOrder.verify(mSemaphore, times(2)).tryAcquire() semaphoreInOrder.verify(mSemaphore, times(2)).release() } @Test fun mainPrintUiLaunchedSuccessfullyLoggedTest() { val logWrapperInOrder = inOrder(mStatsLogWrapper) Loading Loading @@ -155,6 +240,7 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verifyNoInteractions(mHandler) } Loading @@ -168,7 +254,8 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() verify(mSemaphore, times(2)).release() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verify(mSemaphore, times(3)).release() } @Test Loading Loading @@ -201,6 +288,7 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verifyNoInteractions(mHandler) verifyNoInteractions(mSemaphore) verifyNoInteractions(mStatsLogWrapper) Loading Loading
core/java/android/print/PrintAttributes.java +9 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import java.util.Map; */ public final class PrintAttributes implements Parcelable { /** @hide */ // LINT.IfChange @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "COLOR_MODE_" }, value = { COLOR_MODE_MONOCHROME, Loading @@ -62,9 +63,12 @@ public final class PrintAttributes implements Parcelable { private static final int VALID_COLOR_MODES = COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR; // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) /** @hide */ @Retention(RetentionPolicy.SOURCE) // LINT.IfChange @IntDef(flag = true, prefix = { "DUPLEX_MODE_" }, value = { DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, Loading @@ -81,6 +85,8 @@ public final class PrintAttributes implements Parcelable { private static final int VALID_DUPLEX_MODES = DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE; // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) private @Nullable MediaSize mMediaSize; private @Nullable Resolution mResolution; Loading Loading @@ -462,6 +468,7 @@ public final class PrintAttributes implements Parcelable { private static final Map<String, MediaSize> sIdToMediaSizeMap = new ArrayMap<>(); // LINT.IfChange /** * Unknown media size in portrait mode. * <p> Loading Loading @@ -840,6 +847,8 @@ public final class PrintAttributes implements Parcelable { public static final @NonNull MediaSize JPN_OE_PHOTO_L = new MediaSize("JPN_OE_PHOTO_L", "android", R.string.mediasize_japanese_l, 3500, 5000); // Update BuiltInPrintService stats logger too. // LINT.ThenChange(/packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt) private final @NonNull String mId; /**@hide */ Loading
packages/PrintSpooler/src/com/android/printspooler/stats/StatsAsyncLogger.kt +594 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/PrintSpooler/src/com/android/printspooler/stats/StatsLogWrapper.kt +19 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,23 @@ open class StatsLogWrapper { printServiceCount, ) } open fun internalPrinterDiscovery( @UserIdInt printServiceId: Int, supportedColors: Set<StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent>, supportedSizes: Set<StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent>, supportedDuplexModes: Set<StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent>, ) { val colorBits = supportedColors.map { it.rawValue }.toIntArray() val mediaSizes = supportedSizes.map { it.rawValue }.toIntArray() val duplexModes = supportedDuplexModes.map { it.rawValue }.toIntArray() PrintSpoolerStatsLog.write( PrintSpoolerStatsLog.FRAMEWORK_PRINTER_DISCOVERY, printServiceId, colorBits, mediaSizes, duplexModes, ) } }
packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +25 −0 Original line number Diff line number Diff line Loading @@ -2663,6 +2663,31 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } } if (Flags.printingTelemetry()) { for (final PrinterInfo printer : newPrintersMap.values()) { final PrinterCapabilitiesInfo caps = printer.getCapabilities(); int colorModesMask = 0; int duplexModesMask = 0; Set<MediaSize> mediaSizes = new HashSet<>(); if (caps != null) { colorModesMask = caps.getColorModes(); duplexModesMask = caps.getDuplexModes(); mediaSizes = new HashSet<>(caps.getMediaSizes()); } final String serviceName = printer.getId().getServiceName().getPackageName(); try { final int serviceUId = getPackageManager().getApplicationInfo(serviceName, 0).uid; StatsAsyncLogger.INSTANCE .PrinterDiscovery(serviceUId, colorModesMask, duplexModesMask, mediaSizes); } catch (NameNotFoundException e) { Log.e(LOG_TAG, "Failed to get uid for service"); } } } // Add the rest of the new printers, i.e. what is left. addPrinters(newPrinterHolders, newPrintersMap.values()); Loading
packages/PrintSpooler/tests/robolectric/src/com/android/printspooler/stats/StatsAsyncLoggerTest.kt +89 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.printspooler.stats import android.os.Handler import android.print.PrintAttributes import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import java.util.concurrent.Semaphore Loading Loading @@ -61,6 +62,90 @@ open class StatsAsyncLoggerTest { StatsAsyncLogger.stopLogging() } @Test fun printerDiscoverySuccessfullyLoggedTest() { val logWrapperInOrder = inOrder(mStatsLogWrapper) val handlerInOrder = inOrder(mHandler) val semaphoreInOrder = inOrder(mSemaphore) val timeCaptor = argumentCaptor<Long>() val runnableCaptor = argumentCaptor<Runnable>() StatsAsyncLogger.startLogging() StatsAsyncLogger.testSetSemaphore(mSemaphore) StatsAsyncLogger.testSetHandler(mHandler) StatsAsyncLogger.testSetStatsLogWrapper(mStatsLogWrapper) // "foo" printer service: Generally arbitrary arguments focusing more on creating non-empty // lists. val printServiceFoo = 42 val colorsMaskFoo = (PrintAttributes.COLOR_MODE_COLOR or PrintAttributes.COLOR_MODE_MONOCHROME) val supportedMediaSizesFoo = setOf<PrintAttributes.MediaSize>( PrintAttributes.MediaSize.NA_LETTER, PrintAttributes.MediaSize.JPN_HAGAKI, ) val duplexModeMaskFoo = (PrintAttributes.DUPLEX_MODE_LONG_EDGE or PrintAttributes.DUPLEX_MODE_SHORT_EDGE) assertThat( StatsAsyncLogger.PrinterDiscovery( printServiceFoo, colorsMaskFoo, duplexModeMaskFoo, supportedMediaSizesFoo, ) ) .isTrue() // "bar" printer service: Generally arbitrary arguments focusing more on empty/default // values. val printServiceBar = 1337 assertThat(StatsAsyncLogger.PrinterDiscovery(printServiceBar, 0, 0, setOf())).isTrue() handlerInOrder .verify(mHandler, times(2)) .postAtTime(runnableCaptor.capture(), timeCaptor.capture()) handlerInOrder.verifyNoMoreInteractions() // Validate delay args val firstTime = timeCaptor.firstValue val secondTime = timeCaptor.secondValue assertThat(secondTime - firstTime) .isAtLeast(StatsAsyncLogger.EVENT_REPORTED_MIN_INTERVAL.inWholeMilliseconds) assertThat(secondTime - firstTime) .isAtMost(2 * StatsAsyncLogger.EVENT_REPORTED_MIN_INTERVAL.inWholeMilliseconds) // Validate Runnable logic runnableCaptor.firstValue.run() runnableCaptor.secondValue.run() logWrapperInOrder .verify(mStatsLogWrapper) .internalPrinterDiscovery( printServiceFoo, setOf( StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent.COLOR, StatsAsyncLogger.InternalColorModePrinterDiscoveryEvent.MONOCHROME, ), setOf( StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent.NA_LETTER, StatsAsyncLogger.InternalMediaSizePrinterDiscoveryEvent.JPN_HAGAKI, ), setOf( StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent.LONG_EDGE, StatsAsyncLogger.InternalDuplexModePrinterDiscoveryEvent.SHORT_EDGE, ), ) logWrapperInOrder .verify(mStatsLogWrapper) .internalPrinterDiscovery(printServiceBar, setOf(), setOf(), setOf()) logWrapperInOrder.verifyNoMoreInteractions() // Validate Semaphore logic semaphoreInOrder.verify(mSemaphore, times(2)).tryAcquire() semaphoreInOrder.verify(mSemaphore, times(2)).release() } @Test fun mainPrintUiLaunchedSuccessfullyLoggedTest() { val logWrapperInOrder = inOrder(mStatsLogWrapper) Loading Loading @@ -155,6 +240,7 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verifyNoInteractions(mHandler) } Loading @@ -168,7 +254,8 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() verify(mSemaphore, times(2)).release() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verify(mSemaphore, times(3)).release() } @Test Loading Loading @@ -201,6 +288,7 @@ open class StatsAsyncLoggerTest { // Arbitrary Arguments assertThat(StatsAsyncLogger.AdvancedOptionsUiLaunched(42)).isFalse() assertThat(StatsAsyncLogger.MainPrintUiLaunched(setOf(1, 2, 3), 42)).isFalse() assertThat(StatsAsyncLogger.PrinterDiscovery(1337, 0, 0, setOf())).isFalse() verifyNoInteractions(mHandler) verifyNoInteractions(mSemaphore) verifyNoInteractions(mStatsLogWrapper) Loading