text:
<?php

App::uses('Controller', 'Controller');
App::uses('Helper', 'View');
App::uses('AppHelper', 'View/Helper');
App::uses('HtmlHelper', 'View/Helper');
App::uses('FormHelper', 'View/Helper');
App::uses('ClassRegistry', 'Utility');
App::uses('Folder', 'Utility');

App::uses('Bs3HtmlHelper', 'Bs3Helpers.View/Helper');

if (!defined('FULL_BASE_URL')) {
	define('FULL_BASE_URL', 'http://cakephp.org');
}

/**
 * TheHtmlTestController class
 *
 * @package       Cake.Test.Case.View.Helper
 */
class TheHtmlTestController extends Controller {

/**
 * name property
 *
 * @var string
 */
	public $name = 'TheTest';

/**
 * uses property
 *
 * @var mixed null
 */
	public $uses = null;
}

class TestHtmlHelper extends HtmlHelper {

/**
 * expose a method as public
 *
 * @param string $options
 * @param string $exclude
 * @param string $insertBefore
 * @param string $insertAfter
 * @return void
 */
	public function parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) {
		return $this->_parseAttributes($options, $exclude, $insertBefore, $insertAfter);
	}

/**
 * Get a protected attribute value
 *
 * @param string $attribute
 * @return mixed
 */
	public function getAttribute($attribute) {
		if (!isset($this->{$attribute})) {
			return null;
		}
		return $this->{$attribute};
	}

}

/**
 * HtmlHelperTest class
 *
 * @package       Cake.Test.Case.View.Helper
 */
class Bs3HtmlHelperTest extends CakeTestCase {

/**
 * html property
 *
 * @var object
 */
	public $Html = null;

/**
 * setUp method
 *
 * @return void
 */
	public function setUp() {
		parent::setUp();
		$this->View = $this->getMock('View', array('append'), array(new TheHtmlTestController()));
		$this->Html = new Bs3HtmlHelper($this->View);
		$this->Html->request = new CakeRequest(null, false);
		$this->Html->request->webroot = '';

		App::build(array(
			//'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
		));

		//Configure::write('Asset.timestamp', false);
	}

/**
 * tearDown method
 *
 * @return void
 */
	public function tearDown() {
		parent::tearDown();
		unset($this->Html, $this->View);
	}

/**
 * testIcon method
 *
 * @return void
 */
	public function testIcon() {
		$result = $this->Html->icon('fa-home');
		$expected = array(
			'i' => array('class' => 'fa fa-home'),
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->icon('glyphicon-star');
		$expected = array(
			'i' => array('class' => 'glyphicon glyphicon-star'),
		);
		$this->assertTags($result, $expected);

		Configure::write('Bs3.Html.defaultIconVendorPrefix', 'fa');
		$this->Html = new Bs3HtmlHelper($this->View);
		$result = $this->Html->icon('globe');
		$expected = array(
			'i' => array('class' => 'fa fa-globe'),
		);
		$this->assertTags($result, $expected);

		Configure::write('Bs3.Html.defaultIconVendorPrefix', 'glyphicon');
		$this->Html = new Bs3HtmlHelper($this->View);
		$result = $this->Html->icon('leaf');
		$expected = array(
			'i' => array('class' => 'glyphicon glyphicon-leaf'),
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testDropdown() {
		$result = $this->Html->dropdown('My dropdown', array(
			$this->Html->link('Link 1', '/link1'),
			array('html' => $this->Html->link('Link 2', '/link2')),
			array('divider' => true),
			array('html' => $this->Html->link('Link 3', '#', array('class' => 'my-class')), 'divider' => 'after'),
			'Link 4',
			array('html' => $this->Html->link('Link 5', '#'), 'active' => true),
		));
		$expected = array(
			'div' => array('class' => 'dropdown'),
				'button' => array(
					'type' => 'button',
					'class' => 'btn btn-default sr-only dropdown-toggle',
					'data-toggle' => 'dropdown',
				),
					'My dropdown',
					'span' => array('class' => 'caret'),
					'/span',
				'/button',
				'ul' => array('class' => 'dropdown-menu'),
					'
 array('href' => '/link1')),
							'Link 1',
						'/a',
					'/li',
					'
 array('href' => '/link2')),
							'Link 2',
						'/a',
					'/li',
					array('li' => array('class' => 'divider')),
					'/li',
					'
 array('href' => '#', 'class' => 'my-class')),
							'Link 3',
						'/a',
					'/li',
					array('li' => array('class' => 'divider')),
					'/li',
					'
 array('href' => '#')),
							'Link 4',
						'/a',
					'/li',
					array('li' => array('class' => 'active')),
						array('a' => array('href' => '#')),
							'Link 5',
						'/a',
					'/li',
				'/ul',
			'/div',
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testDropdownBlockRendering() {
		$this->Html->dropdownStart('My dropdown');
		echo '
' . $this->Html->link('Link 1', '/link1') . '
';
		echo '
' . $this->Html->link('Link 2', '/link2') . '
';
		echo '

';
		echo '
' . $this->Html->link('Link 3', '#', array('class' => 'my-class')) . '
';
		echo '

';
		echo '
Link 4
';
		echo '
' . $this->Html->link('Link 5', '#') . '
';
		$result = $this->Html->dropdownEnd();
		$expected = array(
			'div' => array('class' => 'dropdown'),
				'button' => array(
					'type' => 'button',
					'class' => 'btn btn-default sr-only dropdown-toggle',
					'data-toggle' => 'dropdown',
				),
					'My dropdown',
					'span' => array('class' => 'caret'),
					'/span',
				'/button',
				'ul' => array('class' => 'dropdown-menu'),
					'
 array('href' => '/link1')),
							'Link 1',
						'/a',
					'/li',
					'
 array('href' => '/link2')),
							'Link 2',
						'/a',
					'/li',
					array('li' => array('class' => 'divider')),
					'/li',
					'
 array('href' => '#', 'class' => 'my-class')),
							'Link 3',
						'/a',
					'/li',
					array('li' => array('class' => 'divider')),
					'/li',
					'
 array('href' => '#')),
							'Link 4',
						'/a',
					'/li',
					array('li' => array('class' => 'active')),
						array('a' => array('href' => '#')),
							'Link 5',
						'/a',
					'/li',
				'/ul',
			'/div',
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testPanel() {
		$result = $this->Html->panelHeading('A panel title');
		$expected = array('div' => array('class' => 'panel-heading'), 'A panel title', '/div');
		$this->assertTags($result, $expected);

		$result = $this->Html->panelBody('A panel body');
		$expected = array('div' => array('class' => 'panel-body'), 'A panel body', '/div');
		$this->assertTags($result, $expected);

		$result = $this->Html->panelHeading('A panel title', array(
			'class' => 'my-panel-heading', 'data-my-value' => '123'
		));
		$expected = array(
			'div' => array(
				'class' => 'my-panel-heading panel-heading',
				'data-my-value' => '123'
			),
			'A panel title',
			'/div'
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->panelBody('A panel body', array(
			'class' => 'my-panel-body', 'data-my-value' => '456'
		));
		$expected = array(
			'div' => array(
				'class' => 'my-panel-body panel-body',
				'data-my-value' => '456'
			),
			'A panel body',
			'/div'
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->panel('A panel title', 'A panel body');
		$expected = array(
			array('div' => array('class' => 'panel-default panel')),
			array('div' => array('class' => 'panel-heading')), 'A panel title', '/div',
			array('div' => array('class' => 'panel-body')), 'A panel body', '/div',
			'/div'
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->panel('A panel title', 'A panel body', array(
			'headingOptions' => array('class' => 'my-panel-heading'),
			'bodyOptions' => array('class' => 'my-panel-body'),
		));
		$expected = array(
			array('div' => array('class' => 'panel-default panel')),
			array('div' => array('class' => 'my-panel-heading panel-heading')), 'A panel title', '/div',
			array('div' => array('class' => 'my-panel-body panel-body')), 'A panel body', '/div',
			'/div'
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testPanelBlockRendering() {
		// Heading rendering
		$this->Html->panelHeadingStart();
		echo $this->Html->tag('div', 'A panel heading with block rendering');
		$result = $this->Html->panelHeadingEnd();
		$expected = array(
			'div' => array('class' => 'panel-heading'),
			'
assertTags($result, $expected);

		// Body rendering
		$this->Html->panelBodyStart();
		echo $this->Html->tag('div', 'A panel body with block rendering');
		$result = $this->Html->panelBodyEnd();
		$expected = array(
			'div' => array('class' => 'panel-body'),
			'
assertTags($result, $expected);

		// Heading with options rendering
		$this->Html->panelHeadingStart(array('class' => 'my-panel-heading'));
		echo $this->Html->tag('div', 'A panel heading with block rendering');
		$result = $this->Html->panelHeadingEnd();
		$expected = array(
			'div' => array('class' => 'my-panel-heading panel-heading'),
			'
assertTags($result, $expected);

		// Body with options rendering
		$this->Html->panelBodyStart();
		echo $this->Html->tag('div', 'A panel body with block rendering');
		$result = $this->Html->panelBodyEnd();
		$expected = array(
			'div' => array('class' => 'panel-body'),
			'
assertTags($result, $expected);

		// Complete panel rendering
		$this->Html->panelStart();
		echo $this->Html->panelHeading('A panel title');
		echo $this->Html->panelBody('A panel body');
		$result = $this->Html->panelEnd();
		$expected = array(
			array('div' => array('class' => 'panel-default panel')),
			array('div' => array('class' => 'panel-heading')), 'A panel title', '/div',
			array('div' => array('class' => 'panel-body')), 'A panel body', '/div',
			'/div'
		);
		$this->assertTags($result, $expected);

		// Complete panel with options rendering
		$this->Html->panelStart(array('class' => 'my-panel'));
		echo $this->Html->panelHeading('A panel title', array('class' => 'my-panel-heading'));
		echo $this->Html->panelBody('A panel body', array('class' => 'my-panel-body'));
		$result = $this->Html->panelEnd();
		$expected = array(
			array('div' => array('class' => 'my-panel panel')),
			array('div' => array('class' => 'my-panel-heading panel-heading')), 'A panel title', '/div',
			array('div' => array('class' => 'my-panel-body panel-body')), 'A panel body', '/div',
			'/div'
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testAccordion() {
		$result = $this->Html->accordion();
		$expected = array(
			'div' => array(
				'class' => 'panel-group',
				'id' => 'preg:/accordion_\w+/'
			),
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->accordionItem('Item title', 'Item body', array('accordionId' => 'my-accordion'));
		$expected = array(
			array('div' => array('class' => 'panel-default panel')),
				array('div' => array('class' => 'panel-heading')),
					array('h4' => array('class' => 'panel-title')),
						array('a' => array(
							'data-parent' => '#my-accordion', 'data-toggle' => 'collapse',
							'href' => 'preg:/\#accordion_body_\w+/'
						)),
							'Item title',
						'/a',
					'/h4',
				'/div',
				array('div' => array('class' => 'panel-collapse collapse in', 'id' => 'preg:/accordion_body_\w+/')),
					array('div' => array('class' => 'panel-body')), 'Item body', '/div',
				'/div',
			'/div',
		);
		$this->assertTags($result, $expected);

		$result = $this->Html->accordion(array(
			'Item 1 title' => 'Item 1 body',
			'Item 2 title' => 'Item 2 body',
		));
		$expected = array(
			'div' => array(
				'class' => 'panel-group',
				'id' => 'preg:/accordion_\w+/'
			),
				array('div' => array('class' => 'panel-default panel')),
					array('div' => array('class' => 'panel-heading')),
						array('h4' => array('class' => 'panel-title')),
							array('a' => array(
								'data-parent' => 'preg:/\#accordion_\w+/', 'data-toggle' => 'collapse',
								'href' => 'preg:/\#accordion_body_\w+/'
							)),
								'Item 1 title',
							'/a',
						'/h4',
					'/div',
					array('div' => array('class' => 'panel-collapse collapse in', 'id' => 'preg:/accordion_body_\w+/')),
						array('div' => array('class' => 'panel-body')), 'Item 1 body', '/div',
					'/div',
				'/div',
				array('div' => array('class' => 'panel-default panel')),
					array('div' => array('class' => 'panel-heading')),
						array('h4' => array('class' => 'panel-title')),
							array('a' => array(
								'data-parent' => 'preg:/\#accordion_\w+/', 'data-toggle' => 'collapse',
								'href' => 'preg:/\#accordion_body_\w+/'
							)),
								'Item 2 title',
							'/a',
						'/h4',
					'/div',
					array('div' => array('class' => 'panel-collapse collapse in', 'id' => 'preg:/accordion_body_\w+/')),
						array('div' => array('class' => 'panel-body')), 'Item 2 body', '/div',
					'/div',
				'/div',
			'/div',
		);
		$this->assertTags($result, $expected);
	}

/**
 * testLink method
 *
 * @return void
 */
	public function testAccordionBlockRendering() {
		$this->Html->accordionStart(array('id' => 'my-accordion'));
			echo $this->Html->accordionItem('Item 1 title', 'Item 1 body', array('accordionId' => 'my-accordion'));
			echo $this->Html->accordionItem('Item 2 title', 'Item 2 body', array('accordionId' => 'my-accordion'));
		$result = $this->Html->accordionEnd();
		$expected = array(
			'div' => array(
				'class' => 'panel-group',
				'id' => 'my-accordion'
			),
				array('div' => array('class' => 'panel-default panel')),
					array('div' => array('class' => 'panel-heading')),
						array('h4' => array('class' => 'panel-title')),
							array('a' => array(
								'data-parent' => '#my-accordion', 'data-toggle' => 'collapse',
								'href' => 'preg:/\#accordion_body_\w+/'
							)),
								'Item 1 title',
							'/a',
						'/h4',
					'/div',
					array('div' => array('class' => 'panel-collapse collapse in', 'id' => 'preg:/accordion_body_\w+/')),
						array('div' => array('class' => 'panel-body')), 'Item 1 body', '/div',
					'/div',
				'/div',
				array('div' => array('class' => 'panel-default panel')),
					array('div' => array('class' => 'panel-heading')),
						array('h4' => array('class' => 'panel-title')),
							array('a' => array(
								'data-parent' => '#my-accordion', 'data-toggle' => 'collapse',
								'href' => 'preg:/\#accordion_body_\w+/'
							)),
								'Item 2 title',
							'/a',
						'/h4',
					'/div',
					array('div' => array('class' => 'panel-collapse collapse in', 'id' => 'preg:/accordion_body_\w+/')),
						array('div' => array('class' => 'panel-body')), 'Item 2 body', '/div',
					'/div',
				'/div',
			'/div',
		);
		$this->assertTags($result, $expected);
	}
}


text:
package es.voghdev.prjdagger2;

import java.util.List;

import es.voghdev.prjdagger2.global.model.User;
import es.voghdev.prjdagger2.usecase.GetUsers;

public class UserListCaller implements GetUsers.Listener {
    List<User> result;
    UserListCollaborator userListCollaborator;

    public UserListCaller(UserListCollaborator userListCollaborator) {
        this.userListCollaborator = userListCollaborator;
    }

    public void getUsers() {
        userListCollaborator.getUsers(this);
    }

    public List<User> getResult() {
        return result;
    }

    @Override
    public void onUsersReceived(List<User> users, boolean isCached) {
        result = users;
    }

    @Override
    public void onError(Exception e) {
        /* Empty */
    }

    @Override
    public void onNoInternetAvailable() {
        /* Empty */
    }
}

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace J2t\Rewardpoints\Controller;

use Magento\Framework\App\RequestInterface;

/**
 * Customer reviews controller
 *
 * @author      Magento Core Team <core@magentocommerce.com>
 */
abstract class Referral extends \Magento\Framework\App\Action\Action
{
    /**
     * Customer session model
     *
     * @var \Magento\Customer\Model\Session
     */
    protected $_customerSession;
    protected $resultPageFactory;

    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Customer\Model\Session $customerSession
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Customer\Model\Session $customerSession
    ) {
        $this->_customerSession = $customerSession;
        parent::__construct($context);
    }

    /**
     * Check customer authentication for some actions
     *
     * @param RequestInterface $request
     * @return \Magento\Framework\App\ResponseInterface
     */
    public function dispatch(RequestInterface $request)
    {
        //echo 'ici';
        //die;
        /*
         * if (!$this->_getCheckout()->getCustomer()->getId()) {
            return $this->_redirect('customer/account/login');
        }
         */
        $loginUrl = $this->_objectManager->get('Magento\Customer\Model\Url')->getLoginUrl();

        if (!$this->_customerSession->authenticate($loginUrl)) {
            $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true);
        }

        /*if (!$this->_customerSession->authenticate($this)) {
            $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true);
        }*/
        return parent::dispatch($request);
    }

}


text:
cd /home/kamil/mgr/cpp/export/farm/jobs/3

 export LD_LIBRARY_PATH=:/usr/local/lib
 ../../../build/exec/Demo input output 10 input/UserFile.xml


text:
using MoarUtils.commands.logging;
using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;

namespace MoarUtils.Utils.Validation {
  public class PhoneNumberValidation {
    public static ValidationResult ValidateUsAndCanada(string number) {
      if (IsValidNorthAmericanNumber(number)) {
        return ValidationResult.Success;
      } else {
        return new ValidationResult(errorMessage);
      }
    }

    public const string errorMessage = "invalid phone number format";
    public const string errorMessageExtended = "invalid phone number format (only US and Canada are supported)";

    public static string StripNonNumericCharacters(string number) {
      string numbersOnly = "";
      for (int i = 0; i < number.Length; i++) {
        numbersOnly += Char.IsNumber(number[i]) ? number[i].ToString() : "";
      }
      return numbersOnly;
    }

    public static bool IsValidNorthAmericanNumber(string number) {
      bool isValid = false;
      try {
        string numbersOnly = StripNonNumericCharacters(number);

        //dnw: 2402164320
        //Regex regexObj = new Regex(@"(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})");
        //http://www.asiteaboutnothing.net/regex/regex-quickstart.html
        Regex regexObj = new Regex(@"^1?([0-9]{3})([0-9]{3})([0-9]{4})$");
        if (regexObj.IsMatch(numbersOnly)) {
          string formattedPhoneNumber = regexObj.Replace(numbersOnly, "($1) $2-$3");
          isValid = true;
        } else {
          // Invalid phone number
        }
      } catch (Exception ex) {
        LogIt.E(ex);
      }
      return isValid;
    }
  }
}


text:
package io.tracee.contextlogger.contextprovider.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * This annotation is used to mark methods that provide context information for context logging.
 * This annotation must reside in classes that are annotated with the
 * {@link TraceeContextProvider} annotation.
 * <p>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
public @interface TraceeContextProviderMethod {

	String displayName();

	boolean enabledPerDefault() default false;

	int order() default 0;

}


text:
@implementation MockStackOverflowManagerDelegate

- (void)fetchingQuestionsFailedWithError:(NSError *)error {
    self.fetchError = error;
}

- (void)didReceiveQuestions:(NSArray *)questions {
    // silence warning
}

- (void)fetchingQuestionBodyFailedWithError:(NSError *)error {
    // silence warning
}

- (void)didReceiveBodyForQuestion:(Question *)question {
    // silence warning
}

@end


text:
package org.joyrest.processor;

import org.joyrest.model.request.InternalRequest;
import org.joyrest.model.response.InternalResponse;
import org.joyrest.model.response.Response;

/**
 * An interface of a processor which is able to generate a correct {@link Response} thank to information provided from the
 * {@link InternalRequest} object.
 *
 * @author pbouda
 */
@FunctionalInterface
public interface RequestProcessor {

    /**
     * Modify {@link InternalResponse response} on the base of the incoming {@link InternalRequest provider}
     * as a abstraction of any server data.
     *
     * @param request incoming model in the form of {@link InternalRequest}
     * @param response response in which is stored a processing result
     * @throws java.lang.Exception exception occurred during processing in joyrest framework
     */
    void process(InternalRequest<Object> request, InternalResponse<Object> response) throws Exception;

}


text:
Three.js on Bower
------

Official repo: https://github.com/mrdoob/three.js#threejs
Official repo is too large on Bower, so I picked files out from that repo.

Current version: [r69](https://github.com/mrdoob/three.js/releases/tag/r69).
In this repo the version in converted to `0.69.0` in semantic version for Bower to recognize.

### Usage

```
bower install --save three.js
```

### Notice

Last time the version was `0.0.68`. However `0.68.0` looks better because the last one is for patch. So there was a switch. Hopefully it doesn't break things.

### License

https://github.com/mrdoob/three.js/blob/master/LICENSE


text:
        <button class="btn btn-primary" data-toggle="modal" data-target="#approveModal" ng-click="selected(task['task-id'])">Approve</button>
        <button class="btn btn-danger" data-toggle="modal" data-target="#rejectModal" ng-click="selected(task['task-id'])">Reject</button>

              {{ task['task-name'] }}

              {{ task['task-description'] }} created at {{task['task-created-on'] | date:'dd.MM.yyyy HH:mm:ss'}}.

No tasks are pending approval at this time.

        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">

        </button>

Approval

        <form class="form-horizontal">

            Comment (optional)

              <textarea rows="5" id="textInput2-modal-markup" class="form-control" ng-model="approveComment"></textarea>

        </form>

        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary" ng-click="approve()" data-dismiss="modal">Approve</button>

        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">

        </button>

Rejection

        <form class="form-horizontal">

            Comment (manadatory)

              <textarea rows="5" id="textInput2-modal-markup" class="form-control" ng-model="rejectComment" required></textarea>

        </form>

        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-danger" ng-click="reject()" data-dismiss="modal">Reject</button>


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:padding="16dp">

  <TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_margin="16dp"
    android:text="Device name will appear here"
    android:textSize="20sp"
    android:textStyle="bold" />

  <EditText
    android:id="@+id/query"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter Model, e.g. 'Pixel'" />

  <Button
    style="@style/Widget.AppCompat.Button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:onClick="query"
    android:text="Query" />

  <View
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_weight="1" />

  <Button
    style="@style/Widget.AppCompat.Button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:onClick="rxExample"
    android:text="What about this device?" />

</LinearLayout>


text:
from django.conf import settings
from django.db import models, connection, transaction
from django.core.management import call_command
from tenant_schemas.postgresql_backend.base import _check_identifier
from tenant_schemas.signals import post_schema_sync
from tenant_schemas.utils import django_is_in_test_mode, schema_exists
from tenant_schemas.utils import get_public_schema_name

class TenantMixin(models.Model):
    auto_drop_schema = False   # USE THIS WITH CAUTION!
                               # set this flag to true on a parent class if
                               # you want the schema to be automatically
                               # removed after tenant remove.

    auto_create_schema = True  # set this flag to false on a parent class if
                               # you dont want the schema to be automatically
                               # created upon save.

    domain_url = models.CharField(max_length=128, unique=True)
    schema_name = models.CharField(max_length=63)

    class Meta:
        abstract = True

    def save(self, verbosity=1, *args, **kwargs):
        is_new = self.pk is None

        if is_new and connection.schema_name != get_public_schema_name():
            raise Exception("Can't create tenant outside the public schema. Current schema is %s."
                            % connection.schema_name)
        elif not is_new and connection.schema_name not in (self.schema_name, get_public_schema_name()):
            raise Exception("Can't update tenant outside it's own schema or the public schema. Current schema is %s."
                            % connection.schema_name)

        super(TenantMixin, self).save(*args, **kwargs)

        if is_new and self.auto_create_schema:
            self.create_schema(check_if_exists=True, verbosity=verbosity)
            post_schema_sync.send(sender=TenantMixin, tenant=self)

    def delete(self, *args, **kwargs):
        """
        Drops the schema related to the tenant instance. Just drop the schema if the parent
        class model has the attribute auto_drop_schema set to True.
        """
        if connection.schema_name not in (self.schema_name, get_public_schema_name()):
            raise Exception("Can't delete tenant outside it's own schema or the public schema. Current schema is %s."
                            % connection.schema_name)

        if schema_exists(self.schema_name) and self.auto_drop_schema:
            cursor = connection.cursor()
            cursor.execute('DROP SCHEMA %s CASCADE' % self.schema_name)
            transaction.commit_unless_managed()

        super(TenantMixin, self).delete(*args, **kwargs)

    def create_schema(self, check_if_exists=False, sync_schema=True, verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if the schema
        already exists before creating it. Returns true if the schema was created, false
        otherwise.
        """

        # safety check
        _check_identifier(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)
        transaction.commit_unless_managed()

        if sync_schema:
            call_command('sync_schemas',
                         schema_name=self.schema_name,
                         tenant=True,
                         public=False,
                         interactive=False,  # don't ask to create an admin user
                         migrate_all=True,  # migrate all apps directly to last version
                         verbosity=verbosity,
                         )

            # fake all migrations
            if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode():
                call_command('migrate_schemas', fake=True, schema_name=self.schema_name, verbosity=verbosity)

        connection.set_schema_to_public()
        return True


text:
ActiveRecord::Schema.define(version: 20161023034522) do

  create_table "consumers", force: :cascade do |t|
    t.string   "first_name",    limit: 255
    t.string   "middle_name",   limit: 255
    t.string   "last_name",     limit: 255
    t.date     "dob"
    t.string   "gender",        limit: 255
    t.string   "email",         limit: 255
    t.string   "phone1",        limit: 255
    t.string   "phone2",        limit: 255
    t.string   "address_1",     limit: 255
    t.string   "address_2",     limit: 255
    t.string   "city",          limit: 255
    t.string   "district",      limit: 255
    t.string   "state",         limit: 255
    t.string   "zipcode",       limit: 255
    t.string   "country",       limit: 255
    t.string   "consumer_type", limit: 255
    t.datetime "created_at",                null: false
    t.datetime "updated_at",                null: false
  end

  create_table "models", force: :cascade do |t|
    t.string   "email",                  limit: 255, default: "", null: false
    t.string   "encrypted_password",     limit: 255, default: "", null: false
    t.string   "reset_password_token",   limit: 255
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          limit: 4,   default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip",     limit: 255
    t.string   "last_sign_in_ip",        limit: 255
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "models", ["email"], name: "index_models_on_email", unique: true, using: :btree
  add_index "models", ["reset_password_token"], name: "index_models_on_reset_password_token", unique: true, using: :btree

  create_table "monthly_power_consumptions", force: :cascade do |t|
    t.float    "kwhpm",       limit: 24
    t.integer  "month_int",   limit: 4
    t.integer  "year",        limit: 4
    t.integer  "consumer_id", limit: 4
    t.datetime "created_at",             null: false
    t.datetime "updated_at",             null: false
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  limit: 255, default: "", null: false
    t.string   "encrypted_password",     limit: 255, default: "", null: false
    t.string   "reset_password_token",   limit: 255
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          limit: 4,   default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip",     limit: 255
    t.string   "last_sign_in_ip",        limit: 255
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

end


text:
import { Session } from '../Session';

export type ProcessString = (text: string[]) => string;
export type ProcessBuffer = (text: Buffer) => Buffer[];

export class ServerSession extends Session {
	async init(clientPublic: string): Promise<void> {
		const sodium = await this.sodium();

		const staticSeed = process.env.STATIC_SEED;

		if (!staticSeed?.trim()) {
			console.error('STATIC_SEED environment variable is required');
			process.exit(1);
		}

		const serverKeypair = await sodium.crypto_kx_seed_keypair(staticSeed + clientPublic);
		this.secretKey = await sodium.crypto_box_secretkey(serverKeypair);
		this.publicKey = await sodium.crypto_box_publickey(serverKeypair);

		const [decryptKey, encryptKey] = await sodium.crypto_kx_server_session_keys(
			this.publicKey,
			this.secretKey,
			this.publicKeyFromString(clientPublic),
		);

		this.decryptKey = decryptKey;
		this.encryptKey = encryptKey;
	}
}


text:
package com.siyeh.ipp.concatenation;

import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import javax.annotation.Nonnull;

import java.util.ArrayList;
import java.util.List;

public class JoinConcatenatedStringLiteralsIntention extends Intention {

  @Override
  @Nonnull
  protected PsiElementPredicate getElementPredicate() {
    return new StringConcatPredicate();
  }

  @Override
  public void processIntention(PsiElement element) throws IncorrectOperationException {
    if (element instanceof PsiWhiteSpace) {
      element = element.getPrevSibling();
    }
    if (!(element instanceof PsiJavaToken)) {
      return;
    }
    final PsiJavaToken token = (PsiJavaToken)element;
    final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)element.getParent();
    StringBuilder newExpression = new StringBuilder();
    final PsiElement[] children = polyadicExpression.getChildren();
    final List<PsiElement> buffer = new ArrayList(3);
    for (PsiElement child : children) {
      if (child instanceof PsiJavaToken) {
        if (token.equals(child)) {
          final PsiLiteralExpression literalExpression = (PsiLiteralExpression)buffer.get(0);
          final Object value = literalExpression.getValue();
          assert value != null;
          newExpression.append('"').append(StringUtil.escapeStringCharacters(value.toString()));
        }
        else {
          for (PsiElement bufferedElement : buffer) {
            newExpression.append(bufferedElement.getText());
          }
          buffer.clear();
          newExpression.append(child.getText());
        }
      }
      else if (child instanceof PsiLiteralExpression) {
        if (buffer.isEmpty()) {
          buffer.add(child);
        }
        else {
          final PsiLiteralExpression literalExpression = (PsiLiteralExpression)child;
          final Object value = literalExpression.getValue();
          assert value != null;
          newExpression.append(StringUtil.escapeStringCharacters(value.toString())).append('"');
          buffer.clear();
        }
      }
      else {
        if (buffer.isEmpty()) {
          newExpression.append(child.getText());
        }
        else {
          buffer.add(child);
        }
      }
    }
    for (PsiElement bufferedElement : buffer) {
      newExpression.append(bufferedElement.getText());
    }
    replaceExpression(newExpression.toString(), polyadicExpression);
  }
}


text:
<?php
/**
 * Class AcknowledgeTransaction
 *
 * @package Freshwork\Transbank
 * @subpackage WebpayStandard
 * @author Gonzalo De Spirito <gonzunigad@gmail.com>
 * @version 0.1 (06/07/2016)
 */

namespace Freshwork\Transbank\WebpayStandard;

/**
 * Class AcknowledgeTransaction
 *
 * @package Freshwork\Transbank\WebpayStandard
 */
class AcknowledgeTransaction
{
    /** @var string $tokenInput Webpay token */
    public $tokenInput;
}


text:
Retrofit
========

Type-safe REST client for Android and Java by Square, Inc.

For more information please see [the website][1].

Download
--------

Download [the latest JAR][2] or grab via Maven:

```xml
<dependency>
    <groupId>com.squareup.retrofit</groupId>
    <artifactId>retrofit</artifactId>
    <version>(insert latest version)</version>
</dependency>
```

License
=======

    Copyright 2013 Square, Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

 [1]: http://square.github.io/retrofit/
 [2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.squareup.retrofit&a=retrofit&v=LATEST


text:
package io.flutter.plugin.editing;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.AdditionalMatchers.gt;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.notNull;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.InputType;
import android.text.Selection;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewStructure;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.android.KeyboardManager;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.systemchannels.TextInputChannel;
import io.flutter.embedding.engine.systemchannels.TextInputChannel.TextEditState;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.JSONMethodCodec;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.platform.PlatformViewsController;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowAutofillManager;
import org.robolectric.shadows.ShadowBuild;
import org.robolectric.shadows.ShadowInputMethodManager;

@Config(
    manifest = Config.NONE,
    shadows = {TextInputPluginTest.TestImm.class, TextInputPluginTest.TestAfm.class})
@RunWith(RobolectricTestRunner.class)
public class TextInputPluginTest {
  @Mock FlutterJNI mockFlutterJni;
  @Mock FlutterLoader mockFlutterLoader;

  // Verifies the method and arguments for a captured method call.
  private void verifyMethodCall(ByteBuffer buffer, String methodName, String[] expectedArgs)
      throws JSONException {
    buffer.rewind();
    MethodCall methodCall = JSONMethodCodec.INSTANCE.decodeMethodCall(buffer);
    assertEquals(methodName, methodCall.method);
    if (expectedArgs != null) {
      JSONArray args = methodCall.arguments();
      assertEquals(expectedArgs.length, args.length());
      for (int i = 0; i < args.length(); i++) {
        assertEquals(expectedArgs[i], args.get(i).toString());
      }
    }
  }

  private static void sendToBinaryMessageHandler(
      BinaryMessenger.BinaryMessageHandler binaryMessageHandler, String method, Object args) {
    MethodCall methodCall = new MethodCall(method, args);
    ByteBuffer encodedMethodCall = JSONMethodCodec.INSTANCE.encodeMethodCall(methodCall);
    binaryMessageHandler.onMessage(
        (ByteBuffer) encodedMethodCall.flip(), mock(BinaryMessenger.BinaryReply.class));
  }

  @Test
  public void textInputPlugin_RequestsReattachOnCreation() throws JSONException {
    // Initialize a general TextInputPlugin.
    InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);

    FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
    DartExecutor dartExecutor = spy(new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
    TextInputChannel textInputChannel = new TextInputChannel(dartExecutor);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    ArgumentCaptor<String> channelCaptor = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<ByteBuffer> bufferCaptor = ArgumentCaptor.forClass(ByteBuffer.class);

    verify(dartExecutor, times(1))
        .send(
            channelCaptor.capture(),
            bufferCaptor.capture(),
            any(BinaryMessenger.BinaryReply.class));
    assertEquals("flutter/textinput", channelCaptor.getValue());
    verifyMethodCall(bufferCaptor.getValue(), "TextInputClient.requestExistingInputState", null);
  }

  @Test
  public void setTextInputEditingState_doesNotInvokeUpdateEditingState() {
    // Initialize a general TextInputPlugin.
    InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            null,
            null));

    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("initial input from framework", 0, 0, -1, -1));
    assertTrue(textInputPlugin.getEditable().toString().equals("initial input from framework"));

    verify(textInputChannel, times(0))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    textInputPlugin.setTextInputEditingState(
        testView,
        new TextInputChannel.TextEditState("more update from the framework", 1, 2, -1, -1));

    assertTrue(textInputPlugin.getEditable().toString().equals("more update from the framework"));
    verify(textInputChannel, times(0))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
  }

  @Test
  public void inputConnectionAdaptor_RepeatFilter() throws NullPointerException {
    // Initialize a general TextInputPlugin.
    InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);
    EditorInfo outAttrs = new EditorInfo();
    outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
    TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    // Change InputTarget to FRAMEWORK_CLIENT.
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false),
            null,
            null,
            null,
            null));

    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    verify(textInputChannel, times(0))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    InputConnectionAdaptor inputConnectionAdaptor =
        (InputConnectionAdaptor)
            textInputPlugin.createInputConnection(testView, mock(KeyboardManager.class), outAttrs);

    inputConnectionAdaptor.beginBatchEdit();
    verify(textInputChannel, times(0))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
    inputConnectionAdaptor.setComposingText("I do not fear computers. I fear the lack of them.", 1);
    verify(textInputChannel, times(0))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
    inputConnectionAdaptor.endBatchEdit();
    verify(textInputChannel, times(1))
        .updateEditingState(
            anyInt(),
            eq("I do not fear computers. I fear the lack of them."),
            eq(49),
            eq(49),
            eq(0),
            eq(49));

    inputConnectionAdaptor.beginBatchEdit();

    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    inputConnectionAdaptor.endBatchEdit();

    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    inputConnectionAdaptor.beginBatchEdit();

    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    inputConnectionAdaptor.setSelection(3, 4);
    assertEquals(Selection.getSelectionStart(textInputPlugin.getEditable()), 3);
    assertEquals(Selection.getSelectionEnd(textInputPlugin.getEditable()), 4);

    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());

    inputConnectionAdaptor.endBatchEdit();

    verify(textInputChannel, times(1))
        .updateEditingState(
            anyInt(),
            eq("I do not fear computers. I fear the lack of them."),
            eq(3),
            eq(4),
            eq(0),
            eq(49));
  }

  @Test
  public void setTextInputEditingState_doesNotRestartWhenTextIsIdentical() {
    // Initialize a general TextInputPlugin.
    InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    // Move the cursor.
    assertEquals(1, testImm.getRestartCount(testView));
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    // Verify that we haven't restarted the input.
    assertEquals(1, testImm.getRestartCount(testView));
  }

  @Test
  public void setTextInputEditingState_alwaysSetEditableWhenDifferent() {
    // Initialize a general TextInputPlugin.
    InputMethodSubtype inputMethodSubtype = mock(InputMethodSubtype.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now. With
    // changed text, we should
    // always set the Editable contents.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("hello", 0, 0, -1, -1));
    assertEquals(1, testImm.getRestartCount(testView));
    assertTrue(textInputPlugin.getEditable().toString().equals("hello"));

    // No pending restart, set Editable contents anyways.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("Shibuyawoo", 0, 0, -1, -1));
    assertEquals(1, testImm.getRestartCount(testView));
    assertTrue(textInputPlugin.getEditable().toString().equals("Shibuyawoo"));
  }

  // See https://github.com/flutter/flutter/issues/29341 and
  // https://github.com/flutter/flutter/issues/31512
  // All modern Samsung keybords are affected including non-korean languages and thus
  // need the restart.
  // Update: many other keyboards need this too:
  // https://github.com/flutter/flutter/issues/78827
  @Test
  public void setTextInputEditingState_restartsIMEOnlyWhenFrameworkChangesComposingRegion() {
    // Initialize a TextInputPlugin that needs to be always restarted.
    InputMethodSubtype inputMethodSubtype =
        new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false),
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    assertEquals(1, testImm.getRestartCount(testView));
    InputConnection connection =
        textInputPlugin.createInputConnection(
            testView, mock(KeyboardManager.class), new EditorInfo());
    connection.setComposingText("POWERRRRR", 1);

    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("UNLIMITED POWERRRRR", 0, 0, 10, 19));
    // Does not restart since the composing text is not changed.
    assertEquals(1, testImm.getRestartCount(testView));

    connection.finishComposingText();
    // Does not restart since the composing text is committed by the IME.
    assertEquals(1, testImm.getRestartCount(testView));

    // Does not restart since the composing text is changed by the IME.
    connection.setComposingText("POWERRRRR", 1);
    assertEquals(1, testImm.getRestartCount(testView));

    // The framework tries to commit the composing region.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("POWERRRRR", 0, 0, -1, -1));

    // Verify that we've restarted the input.
    assertEquals(2, testImm.getRestartCount(testView));
  }

  @Test
  public void TextEditState_throwsOnInvalidStatesReceived() {
    // Index OOB:
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", 0, -9, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", -9, 0, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", 0, 1, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", 1, 0, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, 1, 5));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, 5, 1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, 5, 5));

    // Invalid Selections:
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", -1, -2, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", -2, -1, -1, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("", -9, -9, -1, -1));

    // Invalid Composing Ranges:
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, -9, -1));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, -1, -9));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, -9, -9));
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, 2, 1));
    // A collapsed composing range is invalid.
    assertThrows(IndexOutOfBoundsException.class, () -> new TextEditState("Text", 0, 0, 1, 1));

    // Valid values (does not throw):
    // Nothing selected/composing:
    TextEditState state = new TextEditState("", -1, -1, -1, -1);
    assertEquals("", state.text);
    assertEquals(-1, state.selectionStart);
    assertEquals(-1, state.selectionEnd);
    assertEquals(-1, state.composingStart);
    assertEquals(-1, state.composingEnd);
    // Collapsed selection.
    state = new TextEditState("x", 0, 0, 0, 1);
    assertEquals(0, state.selectionStart);
    assertEquals(0, state.selectionEnd);
    // Reversed Selection.
    state = new TextEditState("REEEE", 4, 2, -1, -1);
    assertEquals(4, state.selectionStart);
    assertEquals(2, state.selectionEnd);
  }

  @Test
  public void setTextInputEditingState_nullInputMethodSubtype() {
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(null);

    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    assertEquals(1, testImm.getRestartCount(testView));
  }

  @Test
  public void destroy_clearTextInputMethodHandler() {
    View testView = new View(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    verify(textInputChannel, times(1))
        .setTextInputMethodHandler(notNull(TextInputChannel.TextInputMethodHandler.class));
    textInputPlugin.destroy();
    verify(textInputChannel, times(1))
        .setTextInputMethodHandler(isNull(TextInputChannel.TextInputMethodHandler.class));
  }

  @Test
  public void inputConnection_createsActionFromEnter() throws JSONException {
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
    View testView = new View(RuntimeEnvironment.application);
    DartExecutor dartExecutor = spy(new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
    TextInputChannel textInputChannel = new TextInputChannel(dartExecutor);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false),
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    ArgumentCaptor<String> channelCaptor = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<ByteBuffer> bufferCaptor = ArgumentCaptor.forClass(ByteBuffer.class);
    verify(dartExecutor, times(1))
        .send(
            channelCaptor.capture(),
            bufferCaptor.capture(),
            any(BinaryMessenger.BinaryReply.class));
    assertEquals("flutter/textinput", channelCaptor.getValue());
    verifyMethodCall(bufferCaptor.getValue(), "TextInputClient.requestExistingInputState", null);
    InputConnectionAdaptor connection =
        (InputConnectionAdaptor)
            textInputPlugin.createInputConnection(
                testView, mock(KeyboardManager.class), new EditorInfo());

    connection.handleKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
    verify(dartExecutor, times(2))
        .send(
            channelCaptor.capture(),
            bufferCaptor.capture(),
            any(BinaryMessenger.BinaryReply.class));
    assertEquals("flutter/textinput", channelCaptor.getValue());
    verifyMethodCall(
        bufferCaptor.getValue(),
        "TextInputClient.performAction",
        new String[] {"0", "TextInputAction.done"});
    connection.handleKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));

    connection.handleKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_NUMPAD_ENTER));
    verify(dartExecutor, times(3))
        .send(
            channelCaptor.capture(),
            bufferCaptor.capture(),
            any(BinaryMessenger.BinaryReply.class));
    assertEquals("flutter/textinput", channelCaptor.getValue());
    verifyMethodCall(
        bufferCaptor.getValue(),
        "TextInputClient.performAction",
        new String[] {"0", "TextInputAction.done"});
  }

  @Test
  public void inputConnection_finishComposingTextUpdatesIMM() throws JSONException {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
      return;
    }
    ShadowBuild.setManufacturer("samsung");
    InputMethodSubtype inputMethodSubtype =
        new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
    Settings.Secure.putString(
        RuntimeEnvironment.application.getContentResolver(),
        Settings.Secure.DEFAULT_INPUT_METHOD,
        "com.sec.android.inputmethod/.SamsungKeypad");
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
    FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
    View testView = new View(RuntimeEnvironment.application);
    DartExecutor dartExecutor = spy(new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
    TextInputChannel textInputChannel = new TextInputChannel(dartExecutor);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false),
            null,
            null,
            null,
            null));
    // There's a pending restart since we initialized the text input client. Flush that now.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("text", 0, 0, -1, -1));
    InputConnection connection =
        textInputPlugin.createInputConnection(
            testView, mock(KeyboardManager.class), new EditorInfo());

    connection.requestCursorUpdates(
        InputConnection.CURSOR_UPDATE_MONITOR | InputConnection.CURSOR_UPDATE_IMMEDIATE);

    connection.finishComposingText();

    assertEquals(-1, testImm.getLastCursorAnchorInfo().getComposingTextStart());
    assertEquals(0, testImm.getLastCursorAnchorInfo().getComposingText().length());
  }

  @Test
  public void inputConnection_textInputTypeNone() {
    View testView = new View(RuntimeEnvironment.application);
    DartExecutor dartExecutor = mock(DartExecutor.class);
    TextInputChannel textInputChannel = new TextInputChannel(dartExecutor);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE, false, false),
            null,
            null,
            null,
            null));

    InputConnection connection =
        textInputPlugin.createInputConnection(
            testView, mock(KeyboardManager.class), new EditorInfo());
    assertEquals(connection, null);
  }

  @Test
  public void showTextInput_textInputTypeNone() {
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    View testView = new View(RuntimeEnvironment.application);
    DartExecutor dartExecutor = mock(DartExecutor.class);
    TextInputChannel textInputChannel = new TextInputChannel(dartExecutor);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            new TextInputChannel.InputType(TextInputChannel.TextInputType.NONE, false, false),
            null,
            null,
            null,
            null));

    textInputPlugin.showTextInput(testView);
    assertEquals(testImm.isSoftInputVisible(), false);
  }

  // -------- Start: Autofill Tests -------
  @Test
  public void autofill_onProvideVirtualViewStructure() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      return;
    }

    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    final TextInputChannel.Configuration.Autofill autofill1 =
        new TextInputChannel.Configuration.Autofill(
            "1", new String[] {"HINT1"}, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    final TextInputChannel.Configuration.Autofill autofill2 =
        new TextInputChannel.Configuration.Autofill(
            "2",
            new String[] {"HINT2", "EXTRA"},
            new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    final TextInputChannel.Configuration config1 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            null);
    final TextInputChannel.Configuration config2 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill2,
            null);

    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            new TextInputChannel.Configuration[] {config1, config2}));

    final ViewStructure viewStructure = mock(ViewStructure.class);
    final ViewStructure[] children = {mock(ViewStructure.class), mock(ViewStructure.class)};

    when(viewStructure.newChild(anyInt()))
        .thenAnswer(invocation -> children[invocation.getArgumentAt(0, int.class)]);

    textInputPlugin.onProvideAutofillVirtualStructure(viewStructure, 0);

    verify(viewStructure).newChild(0);
    verify(viewStructure).newChild(1);

    verify(children[0]).setAutofillId(any(), eq("1".hashCode()));
    verify(children[0]).setAutofillHints(aryEq(new String[] {"HINT1"}));
    verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));

    verify(children[1]).setAutofillId(any(), eq("2".hashCode()));
    verify(children[1]).setAutofillHints(aryEq(new String[] {"HINT2", "EXTRA"}));
    verify(children[1]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
  }

  @Test
  public void autofill_onProvideVirtualViewStructure_single() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      return;
    }

    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    final TextInputChannel.Configuration.Autofill autofill =
        new TextInputChannel.Configuration.Autofill(
            "1", new String[] {"HINT1"}, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    // Autofill should still work without AutofillGroup.
    textInputPlugin.setTextInputClient(
        0,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill,
            null));

    final ViewStructure viewStructure = mock(ViewStructure.class);
    final ViewStructure[] children = {mock(ViewStructure.class)};

    when(viewStructure.newChild(anyInt()))
        .thenAnswer(invocation -> children[invocation.getArgumentAt(0, int.class)]);

    textInputPlugin.onProvideAutofillVirtualStructure(viewStructure, 0);

    verify(viewStructure).newChild(0);

    verify(children[0]).setAutofillId(any(), eq("1".hashCode()));
    verify(children[0]).setAutofillHints(aryEq(new String[] {"HINT1"}));
    // Verifies that the child has a non-zero size.
    verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), gt(0), gt(0));
  }

  @Test
  public void autofill_testLifeCycle() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      return;
    }

    TestAfm testAfm =
        Shadow.extract(RuntimeEnvironment.application.getSystemService(AutofillManager.class));
    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    // Set up an autofill scenario with 2 fields.
    final TextInputChannel.Configuration.Autofill autofill1 =
        new TextInputChannel.Configuration.Autofill(
            "1", new String[] {"HINT1"}, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    final TextInputChannel.Configuration.Autofill autofill2 =
        new TextInputChannel.Configuration.Autofill(
            "2",
            new String[] {"HINT2", "EXTRA"},
            new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    final TextInputChannel.Configuration config1 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            null);
    final TextInputChannel.Configuration config2 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill2,
            null);

    // Set client. This should call notifyViewExited on the FlutterView if the previous client is
    // also eligible for autofill.
    final TextInputChannel.Configuration autofillConfiguration =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            new TextInputChannel.Configuration[] {config1, config2});

    textInputPlugin.setTextInputClient(0, autofillConfiguration);

    // notifyViewExited should not be called as this is the first client we set.
    assertEquals(testAfm.empty, testAfm.exitId);

    // The framework updates the text, call notifyValueChanged.
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("new text", -1, -1, -1, -1));
    assertEquals("new text", testAfm.changeString);
    assertEquals("1".hashCode(), testAfm.changeVirtualId);

    // The input method updates the text, call notifyValueChanged.
    testAfm.resetStates();
    final KeyboardManager mockKeyboardManager = mock(KeyboardManager.class);
    InputConnectionAdaptor adaptor =
        new InputConnectionAdaptor(
            testView,
            0,
            mock(TextInputChannel.class),
            mockKeyboardManager,
            (ListenableEditingState) textInputPlugin.getEditable(),
            new EditorInfo());
    adaptor.commitText("input from IME ", 1);

    assertEquals("input from IME new text", testAfm.changeString);
    assertEquals("1".hashCode(), testAfm.changeVirtualId);

    // notifyViewExited should be called on the previous client.
    testAfm.resetStates();
    textInputPlugin.setTextInputClient(
        1,
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            null,
            null));

    assertEquals("1".hashCode(), testAfm.exitId);

    // TextInputPlugin#clearTextInputClient calls notifyViewExited.
    testAfm.resetStates();
    textInputPlugin.setTextInputClient(3, autofillConfiguration);
    assertEquals(testAfm.empty, testAfm.exitId);
    textInputPlugin.clearTextInputClient();
    assertEquals("1".hashCode(), testAfm.exitId);

    // TextInputPlugin#destroy calls notifyViewExited.
    testAfm.resetStates();
    textInputPlugin.setTextInputClient(4, autofillConfiguration);
    assertEquals(testAfm.empty, testAfm.exitId);
    textInputPlugin.destroy();
    assertEquals("1".hashCode(), testAfm.exitId);
  }

  @Test
  public void autofill_testAutofillUpdatesTheFramework() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      return;
    }

    TestAfm testAfm =
        Shadow.extract(RuntimeEnvironment.application.getSystemService(AutofillManager.class));
    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    // Set up an autofill scenario with 2 fields.
    final TextInputChannel.Configuration.Autofill autofill1 =
        new TextInputChannel.Configuration.Autofill(
            "1",
            new String[] {"HINT1"},
            new TextInputChannel.TextEditState("field 1", 0, 0, -1, -1));
    final TextInputChannel.Configuration.Autofill autofill2 =
        new TextInputChannel.Configuration.Autofill(
            "2",
            new String[] {"HINT2", "EXTRA"},
            new TextInputChannel.TextEditState("field 2", 0, 0, -1, -1));

    final TextInputChannel.Configuration config1 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            null);
    final TextInputChannel.Configuration config2 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill2,
            null);

    final TextInputChannel.Configuration autofillConfiguration =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            new TextInputChannel.Configuration[] {config1, config2});

    textInputPlugin.setTextInputClient(0, autofillConfiguration);
    textInputPlugin.setTextInputEditingState(
        testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

    final SparseArray<AutofillValue> autofillValues = new SparseArray();
    autofillValues.append("1".hashCode(), AutofillValue.forText("focused field"));
    autofillValues.append("2".hashCode(), AutofillValue.forText("unfocused field"));

    // Autofill both fields.
    textInputPlugin.autofill(autofillValues);

    // Verify the Editable has been updated.
    assertTrue(textInputPlugin.getEditable().toString().equals("focused field"));

    // The autofill value of the focused field is sent via updateEditingState.
    verify(textInputChannel, times(1))
        .updateEditingState(anyInt(), eq("focused field"), eq(13), eq(13), eq(-1), eq(-1));

    final ArgumentCaptor<HashMap> mapCaptor = ArgumentCaptor.forClass(HashMap.class);

    verify(textInputChannel, times(1)).updateEditingStateWithTag(anyInt(), mapCaptor.capture());
    final TextInputChannel.TextEditState editState =
        (TextInputChannel.TextEditState) mapCaptor.getValue().get("2");
    assertEquals(editState.text, "unfocused field");
  }

  @Test
  public void autofill_testSetTextIpnutClientUpdatesSideFields() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
      return;
    }

    TestAfm testAfm =
        Shadow.extract(RuntimeEnvironment.application.getSystemService(AutofillManager.class));
    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    // Set up an autofill scenario with 2 fields.
    final TextInputChannel.Configuration.Autofill autofill1 =
        new TextInputChannel.Configuration.Autofill(
            "1", new String[] {"HINT1"}, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
    final TextInputChannel.Configuration.Autofill autofill2 =
        new TextInputChannel.Configuration.Autofill(
            "2",
            new String[] {"HINT2", "EXTRA"},
            new TextInputChannel.TextEditState(
                "Unfocused fields need love like everything does", 0, 0, -1, -1));

    final TextInputChannel.Configuration config1 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            null);
    final TextInputChannel.Configuration config2 =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill2,
            null);

    final TextInputChannel.Configuration autofillConfiguration =
        new TextInputChannel.Configuration(
            false,
            false,
            true,
            TextInputChannel.TextCapitalization.NONE,
            null,
            null,
            null,
            autofill1,
            new TextInputChannel.Configuration[] {config1, config2});

    textInputPlugin.setTextInputClient(0, autofillConfiguration);

    // notifyValueChanged should be called for unfocused fields.
    assertEquals("2".hashCode(), testAfm.changeVirtualId);
    assertEquals("Unfocused fields need love like everything does", testAfm.changeString);
  }
  // -------- End: Autofill Tests -------

  @Test
  public void respondsToInputChannelMessages() {
    ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
        ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
    DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
    TextInputChannel.TextInputMethodHandler mockHandler =
        mock(TextInputChannel.TextInputMethodHandler.class);
    TextInputChannel textInputChannel = new TextInputChannel(mockBinaryMessenger);

    textInputChannel.setTextInputMethodHandler(mockHandler);

    verify(mockBinaryMessenger, times(1))
        .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());

    BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
        binaryMessageHandlerCaptor.getValue();

    sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.requestAutofill", null);
    verify(mockHandler, times(1)).requestAutofill();

    sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.finishAutofillContext", true);
    verify(mockHandler, times(1)).finishAutofillContext(true);

    sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.finishAutofillContext", false);
    verify(mockHandler, times(1)).finishAutofillContext(false);
  }

  @Test
  public void sendAppPrivateCommand_dataIsEmpty() throws JSONException {
    ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
        ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
    DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
    TextInputChannel textInputChannel = new TextInputChannel(mockBinaryMessenger);

    EventHandler mockEventHandler = mock(EventHandler.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setEventHandler(mockEventHandler);

    View testView = new View(RuntimeEnvironment.application);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    verify(mockBinaryMessenger, times(1))
        .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());

    JSONObject arguments = new JSONObject();
    arguments.put("action", "actionCommand");
    arguments.put("data", "");

    BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
        binaryMessageHandlerCaptor.getValue();
    sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.sendAppPrivateCommand", arguments);
    verify(mockEventHandler, times(1))
        .sendAppPrivateCommand(any(View.class), eq("actionCommand"), eq(null));
  }

  @Test
  public void sendAppPrivateCommand_hasData() throws JSONException {
    ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
        ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
    DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
    TextInputChannel textInputChannel = new TextInputChannel(mockBinaryMessenger);

    EventHandler mockEventHandler = mock(EventHandler.class);
    TestImm testImm =
        Shadow.extract(
            RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
    testImm.setEventHandler(mockEventHandler);

    View testView = new View(RuntimeEnvironment.application);
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));

    verify(mockBinaryMessenger, times(1))
        .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());

    JSONObject arguments = new JSONObject();
    arguments.put("action", "actionCommand");
    arguments.put("data", "actionData");

    ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
    BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
        binaryMessageHandlerCaptor.getValue();
    sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.sendAppPrivateCommand", arguments);
    verify(mockEventHandler, times(1))
        .sendAppPrivateCommand(any(View.class), eq("actionCommand"), bundleCaptor.capture());
    assertEquals("actionData", bundleCaptor.getValue().getCharSequence("data"));
  }

  @Test
  @TargetApi(30)
  @Config(sdk = 30)
  public void ime_windowInsetsSync() {
    FlutterView testView = new FlutterView(RuntimeEnvironment.application);
    TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
    TextInputPlugin textInputPlugin =
        new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
    ImeSyncDeferringInsetsCallback imeSyncCallback = textInputPlugin.getImeSyncCallback();
    FlutterEngine flutterEngine =
        spy(new FlutterEngine(RuntimeEnvironment.application, mockFlutterLoader, mockFlutterJni));
    FlutterRenderer flutterRenderer = spy(new FlutterRenderer(mockFlutterJni));
    when(flutterEngine.getRenderer()).thenReturn(flutterRenderer);
    testView.attachToFlutterEngine(flutterEngine);

    WindowInsetsAnimation animation = mock(WindowInsetsAnimation.class);
    when(animation.getTypeMask()).thenReturn(WindowInsets.Type.ime());

    List<WindowInsetsAnimation> animationList = new ArrayList();
    animationList.add(animation);

    WindowInsets.Builder builder = new WindowInsets.Builder();
    WindowInsets noneInsets = builder.build();

    // imeInsets0, 1, and 2 contain unique IME bottom insets, and are used
    // to distinguish which insets were sent at each stage.
    builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 100));
    builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40));
    WindowInsets imeInsets0 = builder.build();

    builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 30));
    builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40));
    WindowInsets imeInsets1 = builder.build();

    builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 50));
    builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 40));
    WindowInsets imeInsets2 = builder.build();

    builder.setInsets(WindowInsets.Type.ime(), Insets.of(0, 0, 0, 200));
    builder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(10, 10, 10, 0));
    WindowInsets deferredInsets = builder.build();

    ArgumentCaptor<FlutterRenderer.ViewportMetrics> viewportMetricsCaptor =
        ArgumentCaptor.forClass(FlutterRenderer.ViewportMetrics.class);

    imeSyncCallback.getInsetsListener().onApplyWindowInsets(testView, deferredInsets);
    imeSyncCallback.getInsetsListener().onApplyWindowInsets(testView, noneInsets);

    verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture());
    assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingTop);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);

    imeSyncCallback.getAnimationCallback().onPrepare(animation);
    imeSyncCallback.getInsetsListener().onApplyWindowInsets(testView, deferredInsets);
    imeSyncCallback.getAnimationCallback().onStart(animation, null);
    // Only the final state call is saved, extra calls are passed on.
    imeSyncCallback.getInsetsListener().onApplyWindowInsets(testView, imeInsets2);

    verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture());
    // No change, as deferredInset is stored to be passed in onEnd()
    assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingTop);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);

    imeSyncCallback.getAnimationCallback().onProgress(imeInsets0, animationList);

    verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture());
    assertEquals(40, viewportMetricsCaptor.getValue().viewPaddingBottom);
    assertEquals(10, viewportMetricsCaptor.getValue().viewPaddingTop);
    assertEquals(60, viewportMetricsCaptor.getValue().viewInsetBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);

    imeSyncCallback.getAnimationCallback().onProgress(imeInsets1, animationList);

    verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture());
    assertEquals(40, viewportMetricsCaptor.getValue().viewPaddingBottom);
    assertEquals(10, viewportMetricsCaptor.getValue().viewPaddingTop);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetBottom); // Cannot be negative
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);

    imeSyncCallback.getAnimationCallback().onEnd(animation);

    verify(flutterRenderer).setViewportMetrics(viewportMetricsCaptor.capture());
    // Values should be of deferredInsets, not imeInsets2
    assertEquals(0, viewportMetricsCaptor.getValue().viewPaddingBottom);
    assertEquals(10, viewportMetricsCaptor.getValue().viewPaddingTop);
    assertEquals(200, viewportMetricsCaptor.getValue().viewInsetBottom);
    assertEquals(0, viewportMetricsCaptor.getValue().viewInsetTop);
  }

  interface EventHandler {
    void sendAppPrivateCommand(View view, String action, Bundle data);
  }

  @Implements(InputMethodManager.class)
  public static class TestImm extends ShadowInputMethodManager {
    private InputMethodSubtype currentInputMethodSubtype;
    private SparseIntArray restartCounter = new SparseIntArray();
    private CursorAnchorInfo cursorAnchorInfo;
    private ArrayList<Integer> selectionUpdateValues;
    private boolean trackSelection = false;
    private EventHandler handler;

    public TestImm() {
      selectionUpdateValues = new ArrayList<Integer>();
    }

    @Implementation
    public InputMethodSubtype getCurrentInputMethodSubtype() {
      return currentInputMethodSubtype;
    }

    @Implementation
    public void restartInput(View view) {
      int count = restartCounter.get(view.hashCode(), /*defaultValue=*/ 0) + 1;
      restartCounter.put(view.hashCode(), count);
    }

    public void setCurrentInputMethodSubtype(InputMethodSubtype inputMethodSubtype) {
      this.currentInputMethodSubtype = inputMethodSubtype;
    }

    public int getRestartCount(View view) {
      return restartCounter.get(view.hashCode(), /*defaultValue=*/ 0);
    }

    public void setEventHandler(EventHandler eventHandler) {
      handler = eventHandler;
    }

    @Implementation
    public void sendAppPrivateCommand(View view, String action, Bundle data) {
      handler.sendAppPrivateCommand(view, action, data);
    }

    @Implementation
    public void updateCursorAnchorInfo(View view, CursorAnchorInfo cursorAnchorInfo) {
      this.cursorAnchorInfo = cursorAnchorInfo;
    }

    // We simply store the values to verify later.
    @Implementation
    public void updateSelection(
        View view, int selStart, int selEnd, int candidatesStart, int candidatesEnd) {
      if (trackSelection) {
        this.selectionUpdateValues.add(selStart);
        this.selectionUpdateValues.add(selEnd);
        this.selectionUpdateValues.add(candidatesStart);
        this.selectionUpdateValues.add(candidatesEnd);
      }
    }

    // only track values when enabled via this.
    public void setTrackSelection(boolean val) {
      trackSelection = val;
    }

    // Returns true if the last updateSelection call passed the following values.
    public ArrayList<Integer> getSelectionUpdateValues() {
      return selectionUpdateValues;
    }

    public CursorAnchorInfo getLastCursorAnchorInfo() {
      return cursorAnchorInfo;
    }
  }

  @Implements(AutofillManager.class)
  public static class TestAfm extends ShadowAutofillManager {
    public static int empty = -999;

    String finishState;
    int changeVirtualId = empty;
    String changeString;

    int enterId = empty;
    int exitId = empty;

    @Implementation
    public void cancel() {
      finishState = "cancel";
    }

    public void commit() {
      finishState = "commit";
    }

    public void notifyViewEntered(View view, int virtualId, Rect absBounds) {
      enterId = virtualId;
    }

    public void notifyViewExited(View view, int virtualId) {
      exitId = virtualId;
    }

    public void notifyValueChanged(View view, int virtualId, AutofillValue value) {
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        return;
      }
      changeVirtualId = virtualId;
      changeString = value.getTextValue().toString();
    }

    public void resetStates() {
      finishState = null;
      changeVirtualId = empty;
      changeString = null;
      enterId = empty;
      exitId = empty;
    }
  }
}