• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

  • Poll Poll
In-app purchases - pricing approach

Individually and cheap or more expensive bundles?

  • Individually and cheap

    Votes: 0 0.0%
  • Costly bundles

    Votes: 0 0.0%

I was wondering what people’s thoughts are on the most effective pricing model for in-app purchases. Do you think you would make more money from pricing items individually and cheaply or bundling all items together for a larger price?

I’m thinking of in-app purchases for cosmetic things such as different color schemes, avatars etc where you could offer $0.50 per color scheme, or unlock all 10 for $2.00 for example.

I think for gaming apps, the little and often approach to unlocking new levels, vehicles etc would certainly win, but I’m less sure with a less ‘addictive’ app.

Annoying connectivity issues

Hi,

I have a Fossil Q Explorist Gen 3 and I have two problems that I think are related. From time to time, I'll notice that my watch doesn't appear to be displaying up to date info, like if I have my phone battery being shown on the watch face, it'll be the % as it was several hours ago. Or maybe it'll occur to me that I haven't felt notifications on my wrist for a while. In any case, I do the following to 'fix' it:

1) On my watch, I go into settings and look at connectivity/wifi. I can see that 'automatic' is selected but the actual SSID displayed underneath might be, say, my home wifi whereas I am now at work. If I just wait a few seconds, it'll update to my work wi-fi...but if it is 'auomatic', surely it should already state my work wifi?
2) On my phone (Honor 9 Lite, Android 9), at this point,if I go into Wear OS. Advanced Settings, it'll often 'hang' if I try to look up my watch battery from there (I use this as a test to see if I can truly connect to my watch). If that's the case, disconnecting and reconnecting to the watch within Wear OS does nothing to help. However, if I turn bluetooth off and on again, connectivity with the watch is restored.

I *think* that I need to do both points 1 and 2 in order to get my watch functioning properly although perhaps point 2 alone would do it.

My question is; are there others out there who have had similar problems and did you do anything that was able to fix it once and for all?

Final point, and I'm not sure if this is the case 100% of the time, but I'm wondering if the problems start after I have used my bluetooth earphones. The phone doesn't throw up any obvious error; my earphones connect fine, I'll listen to music (and the bluetooth indicator states the make of the earphones while I'm connected) and then when I turn my earphones off, all appears to work normally afterwards. I'm just wondering now, as I write this, if my watch issues occur after this...

Thanks for any advice.

Help jp5 tablet heat issue

Sorry for going off topic, but looking to get a real answer to this issue my brother is having.

My brother is in FDOC, he has a JPS5 it is having heat issue, shutting down in 10 minutes . He says the device showed he used 20% of power by just righting an email to me. With that said he says when he can plug it in, the system can show being in red(30%> before plugging in but sometimes show has being (50%<) has soon has plugged in.

It is hard for me to help him without knowing what apps or settings he can use for optimization of the system like cleaning ram and closing down apps running.

He just learned how to delete music he said, not sure if that says he doesn't know much on device or if it's more the way it has to be done with it connected to kiosk.

We are looking into possibly just getting a second player for him, how would any apps, books, music or what have you be handled (be lost?) Or is it kind of like the play store where he could get them back?

Looking for upper lvl support ( Manager to call) today, they happen to be in a meeting at the time, if no call I will call again and see if they are in a meeting again.

Framework reboot due to native crash in zygote crash with SIGSEGV error

Description: Framework reboot due to native crash in zygote crash with SIGSEGV error

Reproduction: Long duration test with multiple apps and reproduction rate – 1/100.

Description:

Below is the tombstone for zygote:

Line 56603:07-08 10:19:39.605 26565 26565 F DEBUG : Build fingerprint: ------------------------------------------------------------------
Line 56604: 07-08 10:19:39.605 26565 26565 F DEBUG : Revision: '0'
Line 56605: 07-08 10:19:39.605 26565 26565 F DEBUG : ABI: 'arm'
Line 56608: 07-08 10:19:39.606 26565 26565 F DEBUG : pid: 652, tid: 26546, name: HeapTaskDaemon >>> zygote <<<
Line 56609: 07-08 10:19:39.606 26565 26565 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x130
Line 56610: 07-08 10:19:39.606 26565 26565 F DEBUG : Cause: null pointer dereference
Line 56611: 07-08 10:19:39.606 26565 26565 F DEBUG : r0 dec0b000 r1 5616eb84 r2 00000007 r3 00000000
Line 56612: 07-08 10:19:39.606 26565 26565 F DEBUG : r4 00000130 r5 cd7929c8 r6 00000000 r7 e4fdc380
Line 56613: 07-08 10:19:39.606 26565 26565 F DEBUG : r8 cd7924bc r9 00000000 r10 00000002 r11 00008a0c
Line 56614: 07-08 10:19:39.607 26565 26565 F DEBUG : ip e49b8974 sp cd7924b0 lr e45e1507 pc e45ec316
Line 56712: 07-08 10:19:39.730 26565 26565 F DEBUG :
Line 56713: 07-08 10:19:39.730 26565 26565 F DEBUG : backtrace:
Line 56715: 07-08 10:19:39.730 26565 26565 F DEBUG : #00 pc 000aa316 /system/lib/libart.so (art::TimingLogger::Reset()+106)
Line 56716: 07-08 10:19:39.730 26565 26565 F DEBUG : #01 pc 0016663b /system/lib/libart.so (art::gc::collector::GarbageCollector::Run(art::gc::GcCause, bool)+178)
Line 56717: 07-08 10:19:39.730 26565 26565 F DEBUG : #02 pc 0018035d /system/lib/libart.so (art::gc::Heap::CollectGarbageInternal(art::gc::collector::GcType, art::gc::GcCause, bool)+2420)
Line 56718: 07-08 10:19:39.730 26565 26565 F DEBUG : #03 pc 0018dbeb /system/lib/libart.so (art::gc::Heap::ConcurrentGC(art::Thread*, art::gc::GcCause, bool)+182)
Line 56719: 07-08 10:19:39.730 26565 26565 F DEBUG : #04 pc 00191b11 /system/lib/libart.so (art::gc::Heap::ConcurrentGCTask::Run(art::Thread*)+20)
Line 56720: 07-08 10:19:39.730 26565 26565 F DEBUG : #05 pc 001aa957 /system/lib/libart.so (art::gc::TaskProcessor::RunAllTasks(art::Thread*)+34)
Line 56721: 07-08 10:19:39.731 26565 26565 F DEBUG : #06 pc 0007463b /system/framework/arm/boot-core-libart.oat (offset 0x73000) (dalvik.system.VMRuntime.clampGrowthLimit [DEDUPED]+74)
Line 56722: 07-08 10:19:39.731 26565 26565 F DEBUG : #07 pc 0014a85d /system/framework/arm/boot-core-libart.oat (offset 0x73000) (java.lang.Daemons$HeapTaskDaemon.runInternal+172)
Line 56723: 07-08 10:19:39.731 26565 26565 F DEBUG : #08 pc 000ec963 /system/framework/arm/boot-core-libart.oat (offset 0x73000) (java.lang.Daemons$Daemon.run+66)
Line 56724: 07-08 10:19:39.731 26565 26565 F DEBUG : #09 pc 002151b1 /system/framework/arm/boot-core-oj.oat (offset 0x106000) (java.lang.Thread.run+64)
Line 56725: 07-08 10:19:39.731 26565 26565 F DEBUG : #10 pc 00411575 /system/lib/libart.so (art_quick_invoke_stub_internal+68)
Line 56726: 07-08 10:19:39.731 26565 26565 F DEBUG : #11 pc 003eb045 /system/lib/libart.so (art_quick_invoke_stub+224)
Line 56727: 07-08 10:19:39.731 26565 26565 F DEBUG : #12 pc 000a183d /system/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+136)
Line 56728: 07-08 10:19:39.731 26565 26565 F DEBUG : #13 pc 003498d5 /system/lib/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+52)
Line 56729: 07-08 10:19:39.731 26565 26565 F DEBUG : #14 pc 0034a62d /system/lib/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+320)
Line 56730: 07-08 10:19:39.731 26565 26565 F DEBUG : #15 pc 0036d0a3 /system/lib/libart.so (art::Thread::CreateCallback(void*)+866)
Line 56731: 07-08 10:19:39.731 26565 26565 F DEBUG : #16 pc 00072dcd /system/lib/libc.so (__pthread_start(void*)+22)
Line 56732: 07-08 10:19:39.731 26565 26565 F DEBUG : #17 pc 0001e3b1 /system/lib/libc.so (__start_thread+24)



One more observation is that we saw few app crashes prior to zygote crash in the path of zygote forking these apps.


pid: 17395, tid: 17395, name: o.android.imoi >>> zygote <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
Cause: null pointer dereference
r0 00000000 r1 8b148311 r2 00000000 r3 00000000
r4 e4bdc424 r5 e4bdc420 r6 e4b97a64 r7 e4bdc3c8
r8 e4bc8000 r9 e4bdc448 r10 00003000 r11 00000003
ip 000000ff sp ffbe1230 lr e41e7dd5 pc e41e7de8

backtrace:
#00 pc 000a8de8 /system/lib/libart.so (art::CumulativeLogger::Reset()+68)
#01 pc 00166901 /system/lib/libart.so (art::gc::collector::GarbageCollector:: ()+192)
#02 pc 0017d853 /system/lib/libart.so (art::gc::Heap::ResetGcPerformanceInfo()+34)
#03 pc 003570db /system/lib/libart.so (art::Runtime::InitNonZygoteOrPostFork(_JNIEnv*, bool, art::Runtime::NativeBridgeAction, char const*, bool)+74)
#04 pc 002e8fb7 /system/lib/libart.so (art::ZygoteHooks_nativePostForkChild(_JNIEnv*, _jclass*, long long, int, unsigned char, unsigned char, _jstring*)+3146)
#05 pc 00074c63 /system/framework/arm/boot-core-libart.oat (offset 0x73000) (dalvik.system.ZygoteHooks.nativePostForkChild+154)
#06 pc 000eba15 /system/framework/arm/boot-core-libart.oat (offset 0x73000) (dalvik.system.ZygoteHooks.postForkChild+68)
#07 pc 00ba0ab9 /system/framework/arm/boot-framework.oat (offset 0x393000) (com.android.internal.os.Zygote.callPostForkChildHooks+80)
#08 pc 00412975 /system/lib/libart.so (art_quick_invoke_stub_internal+68)
#09 pc 003eaec7 /system/lib/libart.so (art_quick_invoke_static_stub+222)
#10 pc 000a184f /system/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+154)
#11 pc 00349655 /system/lib/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+52)
#12 pc 0034947f /system/lib/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+310)
#13 pc 00290219 /system/lib/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+444)
#14 pc 0006e579 /system/lib/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+28)
#15 pc 0011c2ed /system/lib/libandroid_runtime.so ((anonymous namespace)::ForkAndSpecializeCommon(_JNIEnv*, unsigned int, unsigned int, _jintArray*, int, _jobjectArray*, long long, long long, int, _jstring*, _jstring*, bool, _jintArray*, _jintArray*, bool, _jstring*, _jstring*)+4052)
#16 pc 0011ab37 /system/lib/libandroid_runtime.so (android::com_android_internal_os_Zygote_nativeForkAndSpecialize(_JNIEnv*, _jclass*, int, int, _jintArray*, int, _jobjectArray*, int, _jstring*, _jstring*, _jintArray*, _jintArray*, unsigned char, _jstring*, _jstring*)+470)
#17 pc 003b8ba3 /system/framework/arm/boot-framework.oat (offset 0x393000) (com.android.internal.os.Zygote.nativeForkAndSpecialize+338)
#18 pc 00ba3a8b /system/framework/arm/boot-framework.oat (offset 0x393000) (com.android.internal.os.ZygoteConnection.processOneCommand+1450)
#19 pc 00ba7a5b /system/framework/arm/boot-framework.oat (offset 0x393000) (com.android.internal.os.ZygoteServer.runSelectLoop+770)
#20 pc 00ba5269 /system/framework/arm/boot-framework.oat (offset 0x393000) (com.android.internal.os.ZygoteInit.main+1696)
#21 pc 00412975 /system/lib/libart.so (art_quick_invoke_stub_internal+68)
#22 pc 003eaec7 /system/lib/libart.so (art_quick_invoke_static_stub+222)
#23 pc 000a184f /system/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+154)
#24 pc 00349655 /system/lib/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+52)
#25 pc 0034947f /system/lib/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+310)
#26 pc 00290219 /system/lib/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+444)
#27 pc 0006e579 /system/lib/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+28)
#28 pc 0007073b /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+462)
#29 pc 00001c8f /system/bin/app_process32 (main+1122)
#30 pc 000a2245 /system/lib/libc.so (__libc_init+48)
#31 pc 000017eb /system/bin/app_process32 (_start_main+38)
#32 pc 000000c4 <unknown>




Analysis:


Loaded coredump in GDB:


#0 art::TimingLogger::Reset (this=0x130) at art/runtime/base/timing_logger.cc:148
No locals.
#1 0xe46a863e in Reset (this=0x120, gc_cause=<optimized out>, clear_soft_references=<optimized out>) at art/runtime/gc/collector/garbage_collector.cc:49
No locals.
#2 art::gc::collector::GarbageCollector::Run (this=0xe4fdc380, gc_cause=art::gc::kGcCauseBackground, clear_soft_references=true) at art/runtime/gc/collector/garbage_collector.cc:92
start_time = 151785656375586
current_iteration = 0x120
end_time = <optimized out>
self = <optimized out>
#3 0xe46c2360 in art::gc::Heap::CollectGarbageInternal (this=0xe4f3c800, gc_type=art::gc::collector::kGcTypeFull, gc_cause=art::gc::kGcCauseBackground, clear_soft_references=<optimized out>)
at art/runtime/gc/heap.cc:2648
runtime = 0xe4f3c400
self = 0xe42acc00
collector = 0xe4fdc380
#4 0xe46cfbee in art::gc::Heap::ConcurrentGC (this=0xe4f3c800, self=0xe42acc00, cause=art::gc::kGcCauseBackground, force_full=<optimized out>) at art/runtime/gc/heap.cc:3675
next_gc_type = art::gc::collector::kGcTypeSticky
tid = 26546
#5 0xe46d3b14 in art::gc::Heap::ConcurrentGCTask::Run (this=<optimized out>, self=0x5616eb84) at art/runtime/gc/heap.cc:3620
heap = 0xe4f3c800
#6 0xe46ec958 in art::gc::TaskProcessor::RunAllTasks (this=0xe4f30200, self=0xe42acc00) at art/runtime/gc/task_processor.cc:129
task = 0xdec08000
#7 0x720bc63c in ?? ()


From here, we see that at frame 2, current_iteration = 0x120 is holding invalid address, which is a member of garbage collector class, see below code for reference.


In file -- art/runtime/gc/collector/garbage_collector.cc


91 Iteration* current_iteration = GetCurrentIteration();
92 current_iteration->Reset(gc_cause, clear_soft_references);



429 const collector::Iteration* GetCurrentGcIteration() const {
430 return &current_gc_iteration_;
431 }


1254 collector::Iteration current_gc_iteration_;


And we see the collector object being zeroed out, which seems to be the reason for our crash.


gdb) f 2
#2 art::gc::collector::GarbageCollector::Run (this=0xe4fdc380, gc_cause=art::gc::kGcCauseBackground, clear_soft_references=true) at art/runtime/gc/collector/garbage_collector.cc:92
92 in art/runtime/gc/collector/garbage_collector.cc
(gdb) x/100 this
0xe4fdc380: 0 0 0 0
0xe4fdc390: 0 0 0 0
0xe4fdc3a0: 0 0 0 0
0xe4fdc3b0: 0 0 0 0
0xe4fdc3c0: 0 0 0 0
0xe4fdc3d0: 0 0 0 0
0xe4fdc3e0: 0 0 0 0
0xe4fdc3f0: 0 0 0 0
0xe4fdc400: 0 0 0 0
0xe4fdc410: 0 0 0 0
0xe4fdc420: 0 0 0 0
0xe4fdc430: 0 0 0 0
0xe4fdc440: 0 0 0 0
0xe4fdc450: 0 0 0 0
0xe4fdc460: 0 0 0 0
0xe4fdc470: 0 0 0 0
0xe4fdc480: 0 0 0 0
0xe4fdc490: 0 0 0 0
0xe4fdc4a0: 0 0 0 0
0xe4fdc4b0: 0 0 0 0
0xe4fdc4c0: 0 0 0 0
0xe4fdc4d0: 0 0 0 0
0xe4fdc4e0: 0 0 0 0
0xe4fdc4f0: 0 0 0 0

The app crashes seen prior to this zygote crash also seem be to due to similar reason, collector object being NULL.

Debug approaches -
We have internally tried to use ASAN and malloc_debug to check is such corruptions can be caught.
Unfortunately, after enabling malloc_debug, issue was not reproducible.
And with ASAN enablement, device runs slow, and results in other unrelated issues.


Can you please help to provide any debug suggestions/ share any similar instances of this issue ?


Regards,
Deepika

Finding an App

A few years ago, there was a game that I found sweet and cute, and I'm looking to find it again. The only problem is that I've forgotten the name. Does anyone know of an app that involves a little planet you move around, avoid enemies, and it's constantly moving upwards? There are also perks you can unlock.

Thank you!

Can you reset all app notification settings on Android Pie?

Hey Pepz,

I got an Pixel 2 XL with Android Pie on it and I want to reset all my apps notification settings. So what I ultimately want to do is change every apps settings to the same thing basically.

Show notifications: "ON"
Behaviour: "Make sound and pop up on screen"
On lock screen: "Show all notification content"
Sound: "Default notification sound"
Vibrate: "ON"
Blink light: "ON"
and so on...

There doesn't seem to be a way to default every app to have my desired settings (so a global change of the notification default), or is there? Does anyone know an app that can do this?
My goal is to have every app, system apps included, to do the same thing and afterwards change just some single apps to do something else.

So in short: Ignore the default a developer choose for me and override the whole notification settings everywhere to my taste.

(Otherwise I got to change 200+ apps manually and apps like Facebook, Snapchat or Tinder tend to have alot of subcategories so that would take days really
eek.gif
)

Total used of

Total used of

Hello

On my panasonic eluga phone (32 gb internal storage from company), I have formatted sd card (32 gb) as internal.
It is expected that "total used of" should show something like 60 gb or so.
But it still shows 32 gb.

Please help.

PS: It works correctly i.e. shows 60gb on my motorola phone.

Rgds,
A

Attachments

  • Screenshot_20190730-230626.png
    Screenshot_20190730-230626.png
    64.2 KB · Views: 127

Rich People Find Another Loophole...

Ya know, I get it: higher education is expensive, especially at Universities. (Disclaimer: I worked my way through both undergrad and law school with a couple of small loans, my dad had died and there was no way my mom could have funded it.)

Still, that is no justification for what these well-funded (not necessarily wealthy, but certainly rich by most folks' standard) families have done to game the system, taking grants and funds from those who truly are in need. Shameful.

And think about the lesson being (inadvertently?) taught to the kids on both sides. Sad.

“It’s a scam,” said Andy Borst, director of undergraduate admissions at the University of Illinois at Urbana-Champaign. “Wealthy families are manipulating the financial aid process to be eligible for financial aid they would not be otherwise eligible for. They are taking away opportunities from families that really need it.”

Parents Are Giving Up Custody of Their Kids to Get Need-Based College Financial Aid

Does the S9 not support specific Headphone Jack standards?

Hello,

I have a Galaxy S9, headphone jack works fine but I ran into something interesting today. I found my old old wired pair that somehow hasn't got its left earphone inaudible, literally the only pair that has lasted THIS long. But for some reason, it does not work with my Galaxy S9. At first I thought that the pair was dead but I plugged into my computer and it's absolutely fine. So what gives?

Here is a picture of the headphone jack.
20190730_175209.jpg


I'm not really sure what's going on... I tried looking up wiring of a 4-pin headphone jack but I am not sure if there are different standards that have the 4pin jack in common but vary in wiring. Not really experienced in the audio field too much. I am guessing I can solve this issue through a wonderful adapter? Any help is appreciated. Thank you

Before the popularity of smartphones, what are you looking at in the toilet?

Nowadays, the mobile phone and us are inseparable. It can be said that wherever people go, where the mobile phone is brought, even the toilet is not missed.
The thing that could have been done in 3 minutes, since the smartphone was added, the time has been extended to 30 minutes or even longer.
So, before the popularity of smartphones, what are you doing when you go to the toilet?

Copying and Pasting HTML

I have an Android phone that works great, and an Android-powered Samsung Galaxy Tab A. Not sure what number the tablet is. With my phone, I can copy & paste html and it works great, but with my tablet it all comes out as plain text, even though my phone must be about two years older than the tablet. Anyone have any idea if I can change this, and how? I've tried playing around with settings, but have found nothing that works thus far.

Thanks,
Albanate

Input pixels normalization for image recognition app

Hello! I have started my Android app with my custom neural network model saved in .lite format. How can I do a input pixel normalization from 0 to 1 (not from 0 to 255)?
This is my modified ImageClassifier.java from repo: https://github.com/googlecodelabs/tensorflow-for-poets-2
Code:
/** Classifies images with Tensorflow Lite. */
public class ImageClassifier {

  /** Tag for the {@link Log}. */
  private static final String TAG = "TfLiteCameraDemo";

  /** Name of the model file stored in Assets. */
  private static final String MODEL_PATH = "graph.lite";

  /** Name of the label file stored in Assets. */
  private static final String LABEL_PATH = "labels.txt";

  /** Number of results to show in the UI. */
  private static final int RESULTS_TO_SHOW = 1;

  /** Dimensions of inputs. */
  private static final int DIM_BATCH_SIZE = 1;

  private static final int DIM_PIXEL_SIZE = 3;

  static final int DIM_IMG_SIZE_X = 256;
  static final int DIM_IMG_SIZE_Y = 256;

  private static final int IMAGE_MEAN = 128;
  private static final float IMAGE_STD = 128.0f;


  /* Preallocated buffers for storing image data in. */
  private int[] intValues = new int[4*DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y];

  /** An instance of the driver class to run model inference with Tensorflow Lite. */
  private Interpreter tflite;

  /** Labels corresponding to the output of the vision model. */
  private List<String> labelList;

  /** A ByteBuffer to hold image data, to be feed into Tensorflow Lite as inputs. */
  private ByteBuffer imgData = null;

  /** An array to hold inference results, to be feed into Tensorflow Lite as outputs. */
  private float[][] labelProbArray = null;
  /** multi-stage low pass filter **/
  private float[][] filterLabelProbArray = null;
  private static final int FILTER_STAGES = 3;
  private static final float FILTER_FACTOR = 0.4f;

  private PriorityQueue<Map.Entry<String, Float>> sortedLabels =
      new PriorityQueue<>(
          RESULTS_TO_SHOW,
          new Comparator<Map.Entry<String, Float>>() {
            @Override
            public int compare(Map.Entry<String, Float> o1, Map.Entry<String, Float> o2) {
              return (o1.getValue()).compareTo(o2.getValue());
            }
          });

  /** Initializes an {@code ImageClassifier}. */
  ImageClassifier(Activity activity) throws IOException {
    tflite = new Interpreter(loadModelFile(activity));
    labelList = loadLabelList(activity);
    imgData =
        ByteBuffer.allocateDirect(
            4 * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);
    imgData.order(ByteOrder.nativeOrder());
    labelProbArray = new float[1][labelList.size()];
    filterLabelProbArray = new float[FILTER_STAGES][labelList.size()];
    Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
  }

  /** Classifies a frame from the preview stream. */
  String classifyFrame(Bitmap bitmap) {
    if (tflite == null) {
      Log.e(TAG, "Image classifier has not been initialized; Skipped.");
      return "Uninitialized Classifier.";
    }
    convertBitmapToByteBuffer(bitmap);
    // Here's where the magic happens!!!
    long startTime = SystemClock.uptimeMillis();
    tflite.run(imgData, labelProbArray);
    long endTime = SystemClock.uptimeMillis();
    Log.d(TAG, "Timecost to run model inference: " + Long.toString(endTime - startTime));

    // smooth the results
    applyFilter();

    // print the results
    String textToShow = printTopKLabels();
    textToShow = Long.toString(endTime - startTime) + "ms" + textToShow;
    return textToShow;
  }

  void applyFilter(){
    int num_labels =  labelList.size();

    // Low pass filter `labelProbArray` into the first stage of the filter.
    for(int j=0; j<num_labels; ++j){
      filterLabelProbArray[0][j] += FILTER_FACTOR*(labelProbArray[0][j] -
                                                   filterLabelProbArray[0][j]);
    }
    // Low pass filter each stage into the next.
    for (int i=1; i<FILTER_STAGES; ++i){
      for(int j=0; j<num_labels; ++j){
        filterLabelProbArray[i][j] += FILTER_FACTOR*(
                filterLabelProbArray[i-1][j] -
                filterLabelProbArray[i][j]);

      }
    }

    // Copy the last stage filter output back to `labelProbArray`.
    for(int j=0; j<num_labels; ++j){
      labelProbArray[0][j] = filterLabelProbArray[FILTER_STAGES-1][j];
    }
  }

  /** Closes tflite to release resources. */
  public void close() {
    tflite.close();
    tflite = null;
  }

  /** Reads label list from Assets. */
  private List<String> loadLabelList(Activity activity) throws IOException {
    List<String> labelList = new ArrayList<String>();
    BufferedReader reader =
        new BufferedReader(new InputStreamReader(activity.getAssets().open(LABEL_PATH)));
    String line;
    while ((line = reader.readLine()) != null) {
      labelList.add(line);
    }
    reader.close();
    return labelList;
  }

  /** Memory-map the model file in Assets. */
  private MappedByteBuffer loadModelFile(Activity activity) throws IOException {
    AssetFileDescriptor fileDescriptor = activity.getAssets().openFd(MODEL_PATH);
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
    FileChannel fileChannel = inputStream.getChannel();
    long startOffset = fileDescriptor.getStartOffset();
    long declaredLength = fileDescriptor.getDeclaredLength();
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
  }

  /** Writes Image data into a {@code ByteBuffer}. */
  private void convertBitmapToByteBuffer(Bitmap bitmap) {
    if (imgData == null) {
      return;
    }
    imgData.rewind();
    bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    // Convert the image to floating point.
    int pixel = 0;
    long startTime = SystemClock.uptimeMillis();
    for (int i = 0; i < DIM_IMG_SIZE_X; ++i) {
      for (int j = 0; j < DIM_IMG_SIZE_Y; ++j) {
        final int val = intValues[pixel++];
        imgData.putFloat((((val >> 16) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
        imgData.putFloat((((val >> 8) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
        imgData.putFloat((((val) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
      }
    }
    long endTime = SystemClock.uptimeMillis();
    Log.d(TAG, "Timecost to put values into ByteBuffer: " + Long.toString(endTime - startTime));
  }

  /** Prints top-K labels, to be shown in UI as the results. */
  private String printTopKLabels() {
    for (int i = 0; i < labelList.size(); ++i) {
      sortedLabels.add(
          new AbstractMap.SimpleEntry<>(labelList.get(i), labelProbArray[0][i]));
      if (sortedLabels.size() > RESULTS_TO_SHOW) {
        sortedLabels.poll();
      }
    }
    String textToShow = "";
    final int size = sortedLabels.size();
    for (int i = 0; i < size; ++i) {
      Map.Entry<String, Float> label = sortedLabels.poll();
      textToShow = String.format("\n%s: %4.2f",label.getKey(),label.getValue()) + textToShow;
    }
    return textToShow;
  }
}
Where do I need to add normalization option?

Filter

Back
Top Bottom