Categories
discuss

How to detect each RecyclerView item after it is displayed

I want to detect each item in my RecylerView after it is displayed to the user.

Basically, I am trying to play a sound on each item after it is loaded on the screen.

But I am not able to detect whenever each item is loaded on the screen! Is there any method I have to call to detect each item rendered

E.g 1st RecyclerView item displayed -> play sound
    2st RecyclerView item displayed -> play sound...

My Adapter class looks like this –

public class AdapterListAnimation extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<Multiples> items = new ArrayList<>();

    private Context ctx;
    private OnItemClickListener mOnItemClickListener;
    private int animation_type = 0;
    .........
    .........

I am calling this initComponent() method from onCreated() method. Can you give advice on what should I do to achieve my goal as described above?

private void initComponent() {
    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setHasFixedSize(true);
    items = DataGenerator.getPeopleData(this,of,value);
    setAdapter();

    /* MediaPlayer mp=MediaPlayer.create(this, R.raw.sword);
    if (mp.isPlaying()) {
        mp.stop();
        mp.release();
        mp = MediaPlayer.create(this, R.raw.sword);
    } mp.start();*/
}

private void setAdapter() {
    // Set data and list adapter
    mAdapter = new AdapterListAnimation(this, items, animation_type);
    recyclerView.setAdapter(mAdapter);

    // on item list clicked
    mAdapter.setOnItemClickListener(new AdapterListAnimation.OnItemClickListener() {
        @Override
        public void onItemClick(View view, com.math.multiplication.model.Multiples obj, int position) {
            Snackbar.make(parent_view, "Item " + obj.first + " clicked", Snackbar.LENGTH_SHORT).show();
        }
    });
}

Answer

You need to add listener for TTS. Then update your RecyclerView to show right image when speech starts and ends.

I’ve created a test project to show how it can be implemented. Here you can see how it works. Here is my github repository.

Here is main part of my MainActivity class.

private void initTts() {
    tts = new TextToSpeech(this, this);
    tts.setLanguage(Locale.US);
    tts.setOnUtteranceProgressListener(new MyListener());
}

@Override
public void onInit(int status) {
    playSound(0);
}

private void playSound(int index) {
    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(index));
    tts.speak(data.get(index), TextToSpeech.QUEUE_ADD, hashMap);
}

class MyListener extends UtteranceProgressListener {
    @Override
    public void onStart(String utteranceId) {
        int currentIndex = Integer.parseInt(utteranceId);
        mMainAdapter.setCurrentPosition(currentIndex);
        handler.post(new Runnable() {
            @Override
            public void run() {
                mMainAdapter.notifyDataSetChanged();
            }
        });
    }

    @Override
    public void onDone(String utteranceId) {
        int currentIndex = Integer.parseInt(utteranceId);
        mMainAdapter.setCurrentPosition(-1);
        handler.post(new Runnable() {
            @Override
            public void run() {
                mMainAdapter.notifyDataSetChanged();
            }
        });
        if (currentIndex < data.size() - 1) {
            playSound(currentIndex + 1);
        }
    }

    @Override
    public void onError(String utteranceId) {
    }
}
Categories
discuss

Flutter: How do I listen to permissions real time

I am working on an app in which I want to continuously listen to location and battery permissions.

Sample scenario:

  1. The user opens the app
  2. Grants permission access
  3. Goes to settings and revokes the permissions
  4. Opens the app again
  5. The app displays a snackbar that informs the user that permission has been revoked.

I am a beginner and I am using the flutter-permissions-handler and the piece of code below shows my usage.

    _listenForLocationPermission() {
    Future<PermissionStatus> status = PermissionHandler()
        .checkPermissionStatus(PermissionGroup.locationWhenInUse);
    status.then((PermissionStatus status) {
      setState(() {
        _permissionStatus = status;
        if (_permissionStatus != PermissionStatus.granted) {
          _renderOfflineSnackbar('Offline');
        }
      });
    });
  }

Any advice on the above is appreciated.

Answer

I’m in the same boat and have found that this works

You need to extend your class with WidgetsBindingObserver

class _AppState extends State<App> with WidgetsBindingObserver {
  PermissionStatus _status;
  ...
  ...

then add these methods to your class

@override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // check permissions when app is resumed
  // this is when permissions are changed in app settings outside of app
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      PermissionHandler()
          .checkPermissionStatus(PermissionGroup.locationWhenInUse)
          .then(_updateStatus);
    }
  }

My full code is below, but I’ve not included the build widget to keep it brief

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(App());

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> with WidgetsBindingObserver {
  PermissionStatus _status;

  // check permissions
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    PermissionHandler() // Check location permission has been granted
        .checkPermissionStatus(PermissionGroup
            .locationWhenInUse) //check permission returns a Future
        .then(_updateStatus); // handling in callback to prevent blocking UI
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  // check permissions when app is resumed
  // this is when permissions are changed in app settings outside of app
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      PermissionHandler()
          .checkPermissionStatus(PermissionGroup.locationWhenInUse)
          .then(_updateStatus);
    }
  }

override
  Widget build(BuildContext context) {
    return MaterialApp(  
    ...
    ...
}

void _updateStatus(PermissionStatus status) {
    if (status != _status) {
      // check status has changed
      setState(() {
        _status = status; // update
      });
    } else {
      if (status != PermissionStatus.granted) {
        PermissionHandler().requestPermissions(
            [PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
      }
      }
    }
  }

  void _askPermission() {
    PermissionHandler().requestPermissions(
        [PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
  }

  void _onStatusRequested(Map<PermissionGroup, PermissionStatus> statuses) {
    final status = statuses[PermissionGroup.locationWhenInUse];
    if (status != PermissionStatus.granted) {
      // On iOS if "deny" is pressed, open App Settings
      PermissionHandler().openAppSettings();
    } else {
      _updateStatus(status);
    }
  }

I hope this helps

Categories
discuss

How to install APKs from Google Play Console generated from an Android App Bundle?

I currently upload my app updates on the Google Play Console using the publishing format .aab. My problem is I cannot find a way how to download and install the right APKs generated from .aab.

When I download from the “Manage Releases” like many people suggested, it downloads an .aab. When I download a device specific APK, it gives me three APKs. (In my download case, base.apk, config.en.apk, and config.xxhdpi.apk).

The base APK is able to be installed but cannot launch. The other 2 APKs can’t even be parsed. I suspect, these three should be installed as a bundle but I don’t know how to do that.

How can I install these three APKs or download the single APK that I can install easily?

Answer

You can use bundle tool to manipulate the app bundle file and install it on your device locally. First, download bundletool from here. app bundle (the .aab file). Then generate a set of APKs from it by running

bundletool build-apks --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks

Note that the command above creates an APK set of unsigned APKs.

Then you can install this APK by running

bundletool install-apks --apks=/MyApp/my_app.apks

The .apks file contains all configurations. If you want to generate a set of APKs for a specific device, take a look at here.

Categories
discuss

SSLHandshakeException with jlink created runtime

I’ve got a dropwizard app, which runs fine with the standard JRE.

I’ve tried creating a runtime using jlink which is considerably smaller:

/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.scripting,java.security.jgss,java.sql,java.xml,jdk.attach,jdk.jdi,jdk.management,jdk.unsupported --output jre

If I run it with the jlink created runtime it throws this error connecting to redis (which has stunnel in front of it).

ERROR [2019-03-31 09:12:20,080] com.company.project.core.WorkerThread: Failed to process message.
! javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
! at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
! at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(Unknown Source)
! at redis.clients.jedis.util.RedisOutputStream.flushBuffer(RedisOutputStream.java:52)
! at redis.clients.jedis.util.RedisOutputStream.flush(RedisOutputStream.java:133)
! at redis.clients.jedis.Connection.flush(Connection.java:300)
! ... 9 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at redis.clients.jedis.Connection.flush(Connection.java:303)
! at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:235)
! at redis.clients.jedis.BinaryJedis.auth(BinaryJedis.java:2225)
! at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:119)
! at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:888)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:432)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
! at redis.clients.jedis.util.Pool.getResource(Pool.java:50)
! ... 2 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
! at redis.clients.jedis.util.Pool.getResource(Pool.java:59)
! at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)

The stunnel server logs show:

redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG7[23]: TLS alert (write): fatal: handshake failure
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG3[23]: SSL_accept: 141F7065: error:141F7065:SSL routines:final_key_share:no suitable key share
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG5[23]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket

Are there some crypt algorithms being left out by jlink?

Answer

As rich mentions in a comment

Hmmn. If I add jdk.crypto.ec it works – why would jdeps have left that one out, if that one, would there be any others it’s left out?

adding jdk.crypto.ec to the modules list solved the problem.

Categories
discuss

React-Testing-Library: using typescript can’t pass component to render function

I was bootstrapping my first TypeScript + React project from scratch. I was successful with the TypeScript and component rendering. However, as I try to add a test, it just fails with some type errors.

I’ve tried to play around with different configurations, even adding a setupTests.ts file.

Here is my configuration: package.json

{
  ....
      "dependencies": {
        "@babel/plugin-proposal-object-rest-spread": "^7.4.0",
        "@babel/plugin-syntax-dynamic-import": "^7.2.0",
        "@babel/polyfill": "^7.4.0",
        "@babel/preset-env": "^7.4.2",
        "@babel/preset-react": "^7.0.0",
        "@babel/preset-typescript": "^7.3.3",
        "@types/html-webpack-plugin": "^3.2.0",
        "@types/jest": "^24.0.11",
        "@types/react": "^16.8.10",
        "@types/react-dom": "^16.8.3",
        "@types/react-redux": "^7.0.6",
        "@types/react-router-dom": "^4.3.1",
        "@types/redux": "^3.6.0",
        "@types/redux-logger": "^3.0.7",
        "@types/redux-promise": "^0.5.28",
        "@types/webpack": "^4.4.26",
        "@typescript-eslint/eslint-plugin": "^1.5.0",
        "@typescript-eslint/parser": "^1.5.0",
        "babel-jest": "^24.5.0",
        "babel-loader": "^8.0.5",
        "babel-plugin-transform-class-properties": "^6.24.1",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-react": "^6.24.1",
        "eslint": "^5.16.0",
        "eslint-config-prettier": "^4.1.0",
        "eslint-plugin-prettier": "^3.0.1",
        "eslint-plugin-react-hooks": "^1.6.0",
        "html-webpack-plugin": "^3.2.0",
        "jest": "^24.5.0",
        "jest-dom": "^3.1.3",
        "prettier": "^1.16.4",
        "react": "^16.8.6",
        "react-dom": "^16.8.6",
        "react-redux": "^6.0.1",
        "react-router": "^5.0.0",
        "react-router-dom": "^5.0.0",
        "react-testing-library": "^6.0.3",
        "redux": "^4.0.1",
        "redux-logger": "^3.0.6",
        "redux-promise": "^0.6.0",
        "redux-thunk": "^2.3.0",
        "styled-components": "^4.2.0",
        "ts-loader": "^5.3.3",
        "ts-node": "^8.0.3",
        "webpack": "^4.29.6",
        "webpack-dev-middleware": "^3.6.1",
        "webpack-dev-server": "^3.2.1",
        "webpack-hot-middleware": "^2.24.3"
    },
    "devDependencies": {
        "@babel/core": "^7.4.0",
        "awesome-typescript-loader": "^5.2.1",
        "jest-environment-jsdom": "^24.5.0",
        "source-map-loader": "^0.2.4",
        "ts-jest": "^24.0.1",
        "typescript": "^3.4.1",
        "webpack-cli": "^3.3.0"
    }

.babelrc

{
    "presets": [
        "@babel/react",
        "@babel/typescript",
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": [">0.25%"]
                },
                "modules": false,
                "useBuiltIns": "usage"
            }
        ]
    ],
    "plugins": ["@babel/proposal-class-properties", "@babel/proposal-object-rest-spread"]
}

jest.config.js

module.exports = {
    roots: ['<rootDir>/src'],
    transform: {
      '.*.tsx?$': 'ts-jest',
    },
    testMatch: ['<rootDir>/src/**/?(*.)test.{ts,tsx}'],
    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
    setupFilesAfterEnv: [
        'react-testing-library/cleanup-after-each', 'jest-dom/extend-expect']
  };

webpack.config.js:

const path = require('path');

// Plugins
const path = require('path')

// Plugins
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        dev: './src/index.tsx',
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'js/[name].bundle.js',
    },
    devServer: {
        compress: true,
        port: 3000,
        hot: true,
    },
    devtool: 'source-map',
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.jsx'],
    },
    module: {
        rules: [
            /**
             * Gets all .ts, .tsx, or .js files and runs them through eslint
             * and then transpiles them via babel.
             */
            {
                test: /(.js$|.tsx?$)/,
                exclude: /(node_modules|bower_components)/,
                use: ['babel-loader'],
            },

            /**
             * All output '.js' files will have any sourcemaps re-processed by
             * source-map-loader.
             */
            { test: /.js$/, enforce: 'pre', loader: 'source-map-loader' },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html',
        }),
    ],
}

Very basic component to start with:

import React, {SFC} from 'react'

export const Home: SFC<any> = () => <div>HomePage</div>


export default Home

Right when I even try to pass my component as an argument to the render method I get an error

import { Home } from '../pages'; // this import works
import { render } from 'react-testing-library';

describe('', () => {
    test('should render app', () => {
        render(<Home />) // says it cant find "Home"
    });
});

When I run my test I get this from the console:

  ● Test suite failed to run

    TypeScript diagnostics (customize using `[jest-config].globals.ts-jest.diagnostics` option):
    src/__tests__/App.test.ts:6:27 - error TS1005: '>' expected.

    6         console.log(<Home />);
                                ~
    src/__tests__/App.test.ts:6:28 - error TS1161: Unterminated regular expression literal.

    6         console.log(<Home />);

    src/__tests__/App.test.ts:7:5 - error TS1005: ',' expected.

    7     });
          ~
    src/__tests__/App.test.ts:6:22 - error TS2749: 'Home' refers to a value, but is being used as a type here.

    6         console.log(<Home />);
                           ~~~~

UPDATE: currently my file is called App.test.ts

if I change it to App.test.tsx and add import * as React from 'react' to the test the errors go away but the test fails with this error:

  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /<user>/code/react-leader-board/src/__tests__/App.test.tsx:15
            react_testing_library_1.render(<pages_1.Home />);
                                           ^

    SyntaxError: Unexpected token <

      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:451:17)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:493:19)

Answer

I would suggest making sure that your modules are being compiled in the test settings of your env preset:

{
    "presets": [
        "@babel/react",
        "@babel/typescript",
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": [">0.25%"]
                },
                "modules": false,
                "useBuiltIns": "usage"
            }
        ]
    ],
    "plugins": ["@babel/proposal-class-properties", "@babel/proposal-object-rest-spread"],
    "env": {
        "test": {
            "presets": [
                ["@babel/preset-env", {
                    "modules": "commonjs"
                }]
            ]
        }
    }
}

and using babel-jest:

transform: { '\.(ts|tsx)?$': 'babel-jest',`
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..